Documentation
¶
Overview ¶
Package trpcgo is a Go-first tRPC framework that lets you define procedures in Go and automatically generates TypeScript types for @trpc/client.
Write Go structs and handlers, run [trpcgo generate], and get a fully typed TypeScript AppRouter — no manual type definitions needed.
Quick Start ¶
Define a router with procedures:
r := trpcgo.NewRouter(trpcgo.WithDev(true), trpcgo.WithTypeOutput("gen/trpc.ts"))
defer r.Close()
trpcgo.Query(r, "user.get", func(ctx context.Context, input GetUserInput) (User, error) {
return User{ID: input.ID, Name: "Alice"}, nil
})
http.Handle("/trpc/", r.Handler("/trpc"))
Procedures ¶
Six registration functions cover all tRPC procedure types — each returns an error if the path is already registered:
- Query and VoidQuery for read operations (GET)
- Mutation and VoidMutation for write operations (POST)
- Subscribe and VoidSubscribe for real-time streams (SSE)
Must* variants (MustQuery, MustVoidQuery, MustMutation, MustVoidMutation, MustSubscribe, MustVoidSubscribe) panic on duplicate registration and are the idiomatic choice for application bootstrap code.
Use Procedure to create a reusable base procedure that bundles middleware and metadata — the Go equivalent of tRPC's composable procedure builder:
authedProcedure := trpcgo.Procedure().Use(authMiddleware)
adminProcedure := authedProcedure.Use(adminCheck).WithMeta(roleMeta{})
trpcgo.MustQuery(r, "user.list", listUsers, authedProcedure)
trpcgo.MustMutation(r, "admin.ban", banUser, adminProcedure)
Router Options ¶
Configure the router with functional options:
- WithBatching — enable/disable batch request support
- WithMethodOverride — allow POST for queries
- WithMaxBodySize — request body size limit (default 1 MB)
- WithMaxBatchSize — max procedures per batch (default 10)
- WithStrictInput — reject unknown JSON fields
- WithValidator — input validation (e.g. go-playground/validator)
- WithDev — development mode with stack traces and file watcher
- WithErrorFormatter — custom error response shapes
- WithContextCreator — custom context per request
- WithOnError — error callback for logging
- WithSSEPingInterval, WithSSEMaxDuration, WithSSEMaxConnections — SSE tuning
- WithTypeOutput, WithZodOutput, WithZodMini — code generation
- WithWatchPackages — restrict dev watcher to specific package patterns
Middleware ¶
Global middleware applies to all procedures via Router.Use. Per-procedure middleware is set with the Use procedure option. Access procedure metadata with GetProcedureMeta or the typed GetMeta. Compose multiple middleware with Chain.
Error Handling ¶
Return Error values from handlers with JSON-RPC 2.0 error codes. Use NewError, NewErrorf, or WrapError to create errors. All 20 standard tRPC error codes are provided as constants (e.g. CodeNotFound, CodeUnauthorized, CodeTooManyRequests). Use HTTPStatusFromCode and NameFromCode for code conversions.
Merging and Lifecycle ¶
Combine procedures from multiple routers with MergeRouters or Router.Merge. Call Router.Close to stop the file watcher on shutdown.
Server-Side Calls ¶
Invoke procedures from Go without HTTP using Call (typed) or Router.RawCall (untyped). Both run the full middleware chain.
See the project README for full documentation, frontend setup guides, struct tag reference, and working examples: https://github.com/befabri/trpcgo
Index ¶
- func Call[I any, O any](r *Router, ctx context.Context, path string, input I) (O, error)
- func GetMeta[T any](ctx context.Context) (T, bool)
- func GetResponseCookies(ctx context.Context) []*http.Cookie
- func GetResponseHeaders(ctx context.Context) http.Header
- func HTTPStatusFromCode(code ErrorCode) int
- func MustMutation[I any, O any](r *Router, path string, fn func(ctx context.Context, input I) (O, error), ...)
- func MustQuery[I any, O any](r *Router, path string, fn func(ctx context.Context, input I) (O, error), ...)
- func MustSubscribe[I any, O any](r *Router, path string, ...)
- func MustVoidMutation[O any](r *Router, path string, fn func(ctx context.Context) (O, error), ...)
- func MustVoidQuery[O any](r *Router, path string, fn func(ctx context.Context) (O, error), ...)
- func MustVoidSubscribe[O any](r *Router, path string, fn func(ctx context.Context) (<-chan O, error), ...)
- func Mutation[I any, O any](r *Router, path string, fn func(ctx context.Context, input I) (O, error), ...) error
- func NameFromCode(code ErrorCode) string
- func Query[I any, O any](r *Router, path string, fn func(ctx context.Context, input I) (O, error), ...) error
- func SetCookie(ctx context.Context, c *http.Cookie)
- func SetResponseHeader(ctx context.Context, key, value string)
- func Subscribe[I any, O any](r *Router, path string, ...) error
- func VoidMutation[O any](r *Router, path string, fn func(ctx context.Context) (O, error), ...) error
- func VoidQuery[O any](r *Router, path string, fn func(ctx context.Context) (O, error), ...) error
- func VoidSubscribe[O any](r *Router, path string, fn func(ctx context.Context) (<-chan O, error), ...) error
- func WithResponseMetadata(ctx context.Context) context.Context
- type Error
- type ErrorCode
- type ErrorEnvelope
- type ErrorFormatterInput
- type ErrorShape
- type ErrorShapeData
- type HandlerFunc
- type Middleware
- type Option
- func WithBatching(enabled bool) Option
- func WithContextCreator(fn func(ctx context.Context, r *http.Request) context.Context) Option
- func WithDev(enabled bool) Option
- func WithErrorFormatter(fn func(ErrorFormatterInput) any) Option
- func WithMaxBatchSize(n int) Option
- func WithMaxBodySize(n int64) Option
- func WithMethodOverride(enabled bool) Option
- func WithOnError(fn func(ctx context.Context, err *Error, path string)) Option
- func WithSSEMaxConnections(n int) Option
- func WithSSEMaxDuration(d time.Duration) Option
- func WithSSEPingInterval(d time.Duration) Option
- func WithSSEReconnectAfterInactivity(d time.Duration) Option
- func WithStrictInput(enabled bool) Option
- func WithTypeOutput(path string) Option
- func WithValidator(fn func(any) error) Option
- func WithWatchPackages(patterns ...string) Option
- func WithZodMini(enabled bool) Option
- func WithZodOutput(path string) Option
- type ProcedureBuilder
- type ProcedureMeta
- type ProcedureOption
- type ProcedureType
- type Router
- func (r *Router) Close() error
- func (r *Router) GenerateTS(outputPath string) error
- func (r *Router) GenerateZod(outputPath string) error
- func (r *Router) Handler(basePath string) http.Handler
- func (r *Router) Merge(sources ...*Router) error
- func (r *Router) RawCall(ctx context.Context, path string, input json.RawMessage) (any, error)
- func (r *Router) Use(mw ...Middleware)
- type TrackedEvent
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Call ¶
Call invokes a typed procedure by path, running the full middleware chain. Input is marshaled to JSON and the result is unmarshaled to the output type.
Example ¶
package main
import (
"context"
"fmt"
"log"
"github.com/befabri/trpcgo"
)
func main() {
r := trpcgo.NewRouter()
type GreetInput struct {
Name string `json:"name"`
}
trpcgo.Query(r, "greet", func(ctx context.Context, input GreetInput) (string, error) {
return "Hello, " + input.Name + "!", nil
})
// Call invokes a procedure from Go with full type safety.
msg, err := trpcgo.Call[GreetInput, string](r, context.Background(), "greet", GreetInput{Name: "World"})
if err != nil {
log.Fatal(err)
}
fmt.Println(msg)
}
Output: Hello, World!
func GetMeta ¶ added in v0.6.1
GetMeta extracts typed metadata from the procedure context. Returns the zero value and false if the context has no procedure metadata or if the metadata is not of type T.
func GetResponseCookies ¶
GetResponseCookies returns the cookies collected in the context by SetCookie. This is useful for RawCall callers that need to inspect cookies set by handlers. Returns nil if the context does not carry response metadata.
func GetResponseHeaders ¶
GetResponseHeaders returns the headers collected in the context by SetResponseHeader. This is useful for RawCall callers that need to inspect headers set by handlers. Returns nil if the context does not carry response metadata.
func HTTPStatusFromCode ¶
HTTPStatusFromCode returns the HTTP status code for a tRPC error code.
Example ¶
package main
import (
"fmt"
"github.com/befabri/trpcgo"
)
func main() {
status := trpcgo.HTTPStatusFromCode(trpcgo.CodeNotFound)
fmt.Println(status)
}
Output: 404
func MustMutation ¶ added in v0.7.0
func MustMutation[I any, O any](r *Router, path string, fn func(ctx context.Context, input I) (O, error), opts ...ProcedureOption)
MustMutation is like Mutation but panics if registration fails.
func MustQuery ¶ added in v0.7.0
func MustQuery[I any, O any](r *Router, path string, fn func(ctx context.Context, input I) (O, error), opts ...ProcedureOption)
MustQuery is like Query but panics if registration fails. Use in application bootstrap code when a registration error is a programmer mistake.
func MustSubscribe ¶ added in v0.7.0
func MustSubscribe[I any, O any](r *Router, path string, fn func(ctx context.Context, input I) (<-chan O, error), opts ...ProcedureOption)
MustSubscribe is like Subscribe but panics if registration fails.
func MustVoidMutation ¶ added in v0.7.0
func MustVoidMutation[O any](r *Router, path string, fn func(ctx context.Context) (O, error), opts ...ProcedureOption)
MustVoidMutation is like VoidMutation but panics if registration fails.
func MustVoidQuery ¶ added in v0.7.0
func MustVoidQuery[O any](r *Router, path string, fn func(ctx context.Context) (O, error), opts ...ProcedureOption)
MustVoidQuery is like VoidQuery but panics if registration fails.
func MustVoidSubscribe ¶ added in v0.7.0
func MustVoidSubscribe[O any](r *Router, path string, fn func(ctx context.Context) (<-chan O, error), opts ...ProcedureOption)
MustVoidSubscribe is like VoidSubscribe but panics if registration fails.
func Mutation ¶
func Mutation[I any, O any](r *Router, path string, fn func(ctx context.Context, input I) (O, error), opts ...ProcedureOption) error
Mutation registers a mutation procedure. Returns an error if path is already registered.
Example ¶
r := trpcgo.NewRouter()
trpcgo.Mutation(r, "user.create", func(ctx context.Context, input CreateUserInput) (User, error) {
return User{ID: "1", Name: input.Name}, nil
})
user, err := trpcgo.Call[CreateUserInput, User](r, context.Background(), "user.create", CreateUserInput{Name: "Bob"})
if err != nil {
log.Fatal(err)
}
fmt.Println(user.Name)
Output: Bob
func NameFromCode ¶
NameFromCode returns the string name for a tRPC error code (e.g. "NOT_FOUND").
func Query ¶
func Query[I any, O any](r *Router, path string, fn func(ctx context.Context, input I) (O, error), opts ...ProcedureOption) error
Query registers a query procedure. Returns an error if path is already registered.
Example ¶
r := trpcgo.NewRouter()
trpcgo.Query(r, "user.get", func(ctx context.Context, input GetUserInput) (User, error) {
return User{ID: input.ID, Name: "Alice"}, nil
})
// Call the procedure from Go (no HTTP needed).
user, err := trpcgo.Call[GetUserInput, User](r, context.Background(), "user.get", GetUserInput{ID: "1"})
if err != nil {
log.Fatal(err)
}
fmt.Println(user.Name)
Output: Alice
func SetCookie ¶
SetCookie adds a cookie to be set on the HTTP response. Call this from within a procedure handler or middleware. If the context does not carry response metadata (e.g. called outside the HTTP handler), this is a no-op. Safe for concurrent use from JSONL batch handlers.
func SetResponseHeader ¶
SetResponseHeader adds a header value to be set on the HTTP response. If the context does not carry response metadata, this is a no-op. Safe for concurrent use from JSONL batch handlers.
func Subscribe ¶
func Subscribe[I any, O any](r *Router, path string, fn func(ctx context.Context, input I) (<-chan O, error), opts ...ProcedureOption) error
Subscribe registers a subscription procedure. Returns an error if path is already registered.
Example ¶
package main
import (
"context"
"fmt"
"github.com/befabri/trpcgo"
)
func main() {
r := trpcgo.NewRouter()
type EventInput struct {
Topic string `json:"topic"`
}
trpcgo.Subscribe(r, "events", func(ctx context.Context, input EventInput) (<-chan string, error) {
ch := make(chan string)
// In production, send events on ch from a goroutine and close when done.
return ch, nil
})
fmt.Println("subscription registered")
}
Output: subscription registered
func VoidMutation ¶
func VoidMutation[O any](r *Router, path string, fn func(ctx context.Context) (O, error), opts ...ProcedureOption) error
VoidMutation registers a mutation procedure with no input. Returns an error if path is already registered.
func VoidQuery ¶
func VoidQuery[O any](r *Router, path string, fn func(ctx context.Context) (O, error), opts ...ProcedureOption) error
VoidQuery registers a query procedure with no input. Returns an error if path is already registered.
Example ¶
r := trpcgo.NewRouter()
trpcgo.VoidQuery(r, "user.list", func(ctx context.Context) ([]User, error) {
return []User{{ID: "1", Name: "Alice"}, {ID: "2", Name: "Bob"}}, nil
})
users, err := trpcgo.Call[any, []User](r, context.Background(), "user.list", nil)
if err != nil {
log.Fatal(err)
}
fmt.Println(len(users))
Output: 2
func VoidSubscribe ¶
func VoidSubscribe[O any](r *Router, path string, fn func(ctx context.Context) (<-chan O, error), opts ...ProcedureOption) error
VoidSubscribe registers a subscription procedure with no input. Returns an error if path is already registered.
func WithResponseMetadata ¶
WithResponseMetadata injects a fresh responseMetadata into the context. This is called automatically by the HTTP handler. For RawCall, callers should call this before RawCall if they need to access cookies/headers set by handlers via GetResponseCookies/GetResponseHeaders.
Types ¶
type Error ¶
Error represents a tRPC error with a JSON-RPC 2.0 error code.
func NewError ¶
NewError creates a new tRPC error.
Example ¶
package main
import (
"fmt"
"github.com/befabri/trpcgo"
)
func main() {
err := trpcgo.NewError(trpcgo.CodeNotFound, "user not found")
fmt.Println(err)
}
Output: trpc error NOT_FOUND: user not found
func WrapError ¶
WrapError creates a new tRPC error wrapping a cause.
Example ¶
package main
import (
"fmt"
"github.com/befabri/trpcgo"
)
func main() {
cause := fmt.Errorf("connection refused")
err := trpcgo.WrapError(trpcgo.CodeInternalServerError, "database error", cause)
fmt.Println(err)
}
Output: trpc error INTERNAL_SERVER_ERROR: database error: connection refused
type ErrorCode ¶
type ErrorCode int
ErrorCode represents JSON-RPC 2.0 error codes used by the tRPC wire protocol.
const ( CodeParseError ErrorCode = -32700 CodeBadRequest ErrorCode = -32600 CodeInternalServerError ErrorCode = -32603 CodeForbidden ErrorCode = -32003 CodeNotFound ErrorCode = -32004 CodeMethodNotSupported ErrorCode = -32005 CodeTimeout ErrorCode = -32008 CodeConflict ErrorCode = -32009 CodePreconditionFailed ErrorCode = -32012 CodePayloadTooLarge ErrorCode = -32013 CodeUnsupportedMedia ErrorCode = -32015 CodeUnprocessableContent ErrorCode = -32022 CodePreconditionRequired ErrorCode = -32028 CodeTooManyRequests ErrorCode = -32029 CodeClientClosed ErrorCode = -32099 CodeNotImplemented ErrorCode = -32501 CodeBadGateway ErrorCode = -32502 CodeGatewayTimeout ErrorCode = -32504 )
type ErrorEnvelope ¶ added in v0.6.1
type ErrorEnvelope struct {
Error ErrorShape `json:"error"`
}
ErrorEnvelope is the error response envelope following JSON-RPC 2.0 conventions. It is exposed so custom error formatters can inspect or extend the default shape.
type ErrorFormatterInput ¶
type ErrorFormatterInput struct {
Error *Error
Type ProcedureType
Path string
Input json.RawMessage // raw JSON input; nil for pre-execution errors
Ctx context.Context
Shape ErrorEnvelope // the default tRPC error shape
}
ErrorFormatterInput is passed to a custom error formatter. It includes the default error shape so the formatter can extend or replace it.
Security: Ctx carries the full request context, which may contain auth tokens or other sensitive values. Avoid including context values in formatted error responses.
type ErrorShape ¶ added in v0.6.1
type ErrorShape struct {
Code ErrorCode `json:"code"`
Message string `json:"message"`
Data ErrorShapeData `json:"data"`
}
ErrorShape is the error object within an ErrorEnvelope.
type ErrorShapeData ¶ added in v0.6.1
type ErrorShapeData struct {
Code string `json:"code"`
HTTPStatus int `json:"httpStatus"`
Path string `json:"path,omitempty"`
Stack string `json:"stack,omitempty"`
}
ErrorShapeData contains machine-readable error metadata.
type HandlerFunc ¶
HandlerFunc is the procedure handler signature. The input parameter is the already-decoded struct (or nil for void procedures). Middleware receives the same decoded input — no json.RawMessage at any layer.
type Middleware ¶
type Middleware func(next HandlerFunc) HandlerFunc
Middleware wraps a procedure handler, enabling cross-cutting concerns like logging, authentication, and error handling.
func Chain ¶
func Chain(mws ...Middleware) Middleware
Chain composes multiple middleware into one, applied left-to-right.
Example ¶
package main
import (
"context"
"fmt"
"log"
"github.com/befabri/trpcgo"
)
func main() {
r := trpcgo.NewRouter()
logger := func(next trpcgo.HandlerFunc) trpcgo.HandlerFunc {
return func(ctx context.Context, input any) (any, error) {
fmt.Println("log")
return next(ctx, input)
}
}
timer := func(next trpcgo.HandlerFunc) trpcgo.HandlerFunc {
return func(ctx context.Context, input any) (any, error) {
fmt.Println("time")
return next(ctx, input)
}
}
// Chain composes middleware left-to-right.
r.Use(trpcgo.Chain(logger, timer))
trpcgo.VoidQuery(r, "ping", func(ctx context.Context) (string, error) {
return "pong", nil
})
result, err := trpcgo.Call[any, string](r, context.Background(), "ping", nil)
if err != nil {
log.Fatal(err)
}
fmt.Println(result)
}
Output: log time pong
type Option ¶
type Option func(*routerOptions)
Option configures a Router.
func WithBatching ¶
WithBatching enables or disables batch request support.
func WithContextCreator ¶
WithContextCreator sets a function that creates the base context for each request. The ctx argument is the request's existing context (r.Context()), so values and cancellation propagate automatically when the returned context is derived from it.
func WithDev ¶
WithDev enables development mode. When true, error responses include Go stack traces in the data.stack field, matching tRPC's isDev behavior.
func WithErrorFormatter ¶
func WithErrorFormatter(fn func(ErrorFormatterInput) any) Option
WithErrorFormatter sets a custom error formatter that transforms error responses. The function receives the default error shape and can return a modified or entirely different shape. This matches tRPC's errorFormatter.
func WithMaxBatchSize ¶
WithMaxBatchSize sets the maximum number of procedures allowed in a single batch request. Default is 10. Set to -1 for no limit. Passing 0 keeps the default.
func WithMaxBodySize ¶
WithMaxBodySize sets the maximum allowed request body size in bytes. Default is 1 MB. Set to -1 for no limit. Passing 0 keeps the default.
func WithMethodOverride ¶
WithMethodOverride allows clients to override HTTP method (send queries as POST).
func WithOnError ¶
WithOnError sets a callback invoked when a procedure returns an error.
func WithSSEMaxConnections ¶ added in v0.6.1
WithSSEMaxConnections sets the maximum number of concurrent SSE subscriptions. When the limit is reached, new subscription requests are rejected with a TOO_MANY_REQUESTS (429) error. Default is 0 (unlimited). Set to -1 to explicitly disable the limit. Passing 0 keeps the default.
func WithSSEMaxDuration ¶
WithSSEMaxDuration sets the maximum duration for SSE subscriptions. After this duration the server sends a "return" event and closes the connection; the tRPC client will automatically reconnect. Default is 30 minutes. Set to -1 for unlimited. Passing 0 keeps the default.
func WithSSEPingInterval ¶
WithSSEPingInterval sets the keep-alive ping interval for SSE subscriptions. Default is 10 seconds.
func WithSSEReconnectAfterInactivity ¶
WithSSEReconnectAfterInactivity tells the client to reconnect after the given duration of inactivity. This is sent in the SSE connected event as reconnectAfterInactivityMs, matching tRPC's protocol. Default is 0 (disabled).
func WithStrictInput ¶ added in v0.3.0
WithStrictInput enables strict JSON input parsing. When true, procedure inputs that contain unknown fields (fields not present in the input struct) are rejected with a BAD_REQUEST error. This uses json.Decoder's DisallowUnknownFields under the hood.
By default, Go's json.Unmarshal silently ignores unknown fields.
func WithTypeOutput ¶
WithTypeOutput enables automatic TypeScript type generation. When set, calling Router.Handler() writes the TypeScript AppRouter type file to the given path. Use with the top-level registration functions (Query, Mutation, Subscribe, etc.) to capture type info.
func WithValidator ¶
WithValidator sets a function that validates procedure inputs. The function is called with the deserialized input struct after JSON unmarshaling. Only struct-typed inputs are validated; primitives are skipped.
This matches go-playground/validator directly — pass validate.V.Struct:
router := trpcgo.NewRouter(trpcgo.WithValidator(validate.V.Struct))
func WithWatchPackages ¶ added in v0.7.0
WithWatchPackages restricts dev watcher + static regeneration to the given Go package patterns (go/packages syntax, e.g. "./cmd/api", "./internal/...").
When unset, the watcher auto-detects Go directories under the working directory. This option is only used by the dev watcher path (WithDev + WithTypeOutput).
func WithZodMini ¶
WithZodMini switches Zod schema output to zod/mini functional syntax. Only has effect when WithZodOutput is also set.
func WithZodOutput ¶
WithZodOutput enables automatic Zod schema generation alongside TypeScript types. Requires WithTypeOutput to be set. The file watcher regenerates both files when Go source changes are detected.
type ProcedureBuilder ¶ added in v0.7.1
type ProcedureBuilder struct {
// contains filtered or unexported fields
}
ProcedureBuilder is a reusable base procedure that accumulates middleware and metadata. It is immutable: every chain method returns a new instance. A *ProcedureBuilder satisfies ProcedureOption and can be passed directly to any registration function.
Usage:
authedProcedure := trpcgo.Procedure().Use(authMiddleware)
adminProcedure := authedProcedure.Use(adminCheck).WithMeta(roleMeta{})
trpcgo.MustQuery(router, "user.list", listUsers, authedProcedure)
trpcgo.MustMutation(router, "admin.ban", banUser, adminProcedure)
func Procedure ¶ added in v0.7.1
func Procedure(base ...ProcedureOption) *ProcedureBuilder
Procedure creates a new ProcedureBuilder, optionally pre-seeded with existing options or other builders.
func (*ProcedureBuilder) Use ¶ added in v0.7.1
func (b *ProcedureBuilder) Use(mw ...Middleware) *ProcedureBuilder
Use returns a new ProcedureBuilder with the given middleware appended. The receiver is not modified.
func (*ProcedureBuilder) WithMeta ¶ added in v0.7.1
func (b *ProcedureBuilder) WithMeta(meta any) *ProcedureBuilder
WithMeta returns a new ProcedureBuilder with the metadata set. The receiver is not modified.
type ProcedureMeta ¶
type ProcedureMeta struct {
Path string
Type ProcedureType
Meta any // user-defined metadata from WithMeta()
}
ProcedureMeta contains procedure metadata available to middleware via context. Use GetProcedureMeta(ctx) to read it inside middleware.
func GetProcedureMeta ¶
func GetProcedureMeta(ctx context.Context) (ProcedureMeta, bool)
GetProcedureMeta returns the procedure metadata from the context. Returns false if not available (e.g., outside a procedure call).
type ProcedureOption ¶
type ProcedureOption interface {
// contains filtered or unexported methods
}
ProcedureOption configures a single procedure registration. Implement this interface via Use, WithMeta, or Procedure.
func Use ¶
func Use(mw ...Middleware) ProcedureOption
Use adds per-procedure middleware. It can be passed directly to any registration function or to Procedure when building a base procedure.
func WithMeta ¶
func WithMeta(meta any) ProcedureOption
WithMeta attaches metadata to a procedure, accessible in middleware via GetProcedureMeta.
type ProcedureType ¶
type ProcedureType string
ProcedureType distinguishes queries, mutations, and subscriptions.
const ( ProcedureQuery ProcedureType = "query" ProcedureMutation ProcedureType = "mutation" ProcedureSubscription ProcedureType = "subscription" )
type Router ¶
type Router struct {
// contains filtered or unexported fields
}
Router holds registered procedures and produces an http.Handler implementing the tRPC HTTP wire protocol.
func MergeRouters ¶
MergeRouters creates a new Router combining procedures from all sources. Returns an error if any two routers define a procedure at the same path. The returned router has default options and no global middleware.
Example ¶
users := trpcgo.NewRouter()
trpcgo.VoidQuery(users, "user.list", func(ctx context.Context) ([]User, error) {
return nil, nil
})
posts := trpcgo.NewRouter()
trpcgo.VoidQuery(posts, "post.list", func(ctx context.Context) ([]string, error) {
return nil, nil
})
// Merge combines procedures from multiple routers.
app, err := trpcgo.MergeRouters(users, posts)
if err != nil {
fmt.Println(err)
return
}
_ = app.Handler("/trpc")
fmt.Println("merged")
Output: merged
func NewRouter ¶
NewRouter creates a new Router with the given options.
Example ¶
r := trpcgo.NewRouter(
trpcgo.WithBatching(true),
trpcgo.WithDev(true),
)
trpcgo.Query(r, "user.get", func(ctx context.Context, input GetUserInput) (User, error) {
return User{ID: input.ID, Name: "Alice"}, nil
})
fmt.Println("router created")
Output: router created
func (*Router) Close ¶ added in v0.6.1
Close stops the file watcher goroutine (if running) and releases resources. Safe to call multiple times.
func (*Router) GenerateTS ¶
GenerateTS writes TypeScript type definitions for all registered procedures. Procedures must be registered via the top-level functions (Query, Mutation, etc.) to have type information available.
func (*Router) GenerateZod ¶ added in v0.4.0
GenerateZod writes Zod validation schemas for all registered procedure input types. Uses the same reflect-based type information as GenerateTS, enriched with Go kind and validate tag metadata.
If no procedures have typed inputs (all void), no file is written and nil is returned. Use WithZodMini to switch to zod/mini functional syntax.
func (*Router) Handler ¶
Handler returns an http.Handler that serves all registered procedures. basePath is stripped from incoming request URLs before procedure lookup.
When WithDev and WithTypeOutput are both set, the TypeScript type file is generated and a file watcher is started to regenerate types when Go source changes. Call Close() to stop the watcher.
func (*Router) Merge ¶
Merge copies all procedures from the source routers into this router. Returns an error if any procedure path already exists. The operation is atomic: on error, no procedures are added. Global middleware and options on source routers are NOT copied.
func (*Router) RawCall ¶
RawCall invokes a procedure by path, running the full middleware chain. This is the server-side equivalent of an HTTP call — no network involved.
Subscriptions are not supported via RawCall; use the subscription handler directly.
func (*Router) Use ¶
func (r *Router) Use(mw ...Middleware)
Use adds global middleware that applies to all procedures.
Example ¶
package main
import (
"context"
"fmt"
"log"
"github.com/befabri/trpcgo"
)
func main() {
r := trpcgo.NewRouter()
// Add a logging middleware to all procedures.
r.Use(func(next trpcgo.HandlerFunc) trpcgo.HandlerFunc {
return func(ctx context.Context, input any) (any, error) {
meta, _ := trpcgo.GetProcedureMeta(ctx)
fmt.Printf("calling %s\n", meta.Path)
return next(ctx, input)
}
})
trpcgo.VoidQuery(r, "health", func(ctx context.Context) (string, error) {
return "ok", nil
})
result, err := trpcgo.Call[any, string](r, context.Background(), "health", nil)
if err != nil {
log.Fatal(err)
}
fmt.Println(result)
}
Output: calling health ok
type TrackedEvent ¶
TrackedEvent wraps a value with an ID for SSE reconnection support. When the client disconnects and reconnects, it sends the last received ID back in the input (as lastEventId), allowing the handler to resume from where it left off.
func Tracked ¶
func Tracked[T any](id string, data T) TrackedEvent[T]
Tracked creates a TrackedEvent that associates an ID with data. The ID is sent as the SSE id field, enabling client reconnection.