Documentation
¶
Overview ¶
Package router implements a tRPC-compatible RPC server for Go.
It provides type-safe procedure registration using Go generics, middleware support, Server-Sent Events for subscriptions, batch request handling, and CORS configuration.
Basic Usage ¶
r := router.NewRouter()
router.Query(r, "getUser", func(ctx context.Context, input GetUserInput) (User, error) {
return db.FindUser(input.ID)
})
router.Mutation(r, "createUser", func(ctx context.Context, input CreateUserInput) (User, error) {
return db.CreateUser(input)
})
http.ListenAndServe(":8080", r.Handler())
Middleware ¶
Middlewares wrap procedure handlers and can reject requests, enrich context, or add logging/metrics:
r.Use(router.BearerAuth(validateToken)) r.Use(router.RateLimit(100))
Subscriptions ¶
Subscriptions return a channel that is streamed as Server-Sent Events:
router.Subscription(r, "events", func(ctx context.Context, input struct{}) (<-chan Event, error) {
ch := make(chan Event)
go produceEvents(ctx, ch)
return ch, nil
})
Nested Routers ¶
Routers can be merged under namespace prefixes:
appRouter.Merge("user", userRouter) // user.get, user.create, etc.
Index ¶
- Constants
- Variables
- func AddHeader(ctx context.Context, key, value string)
- func GetBearerToken(ctx context.Context) string
- func GetClientIP(ctx context.Context) string
- func GetCookie(ctx context.Context, name string) string
- func GetHeader(ctx context.Context, key string) string
- func GetHeaders(ctx context.Context) http.Header
- func GetLastEventID(ctx context.Context) string
- func GetProcedureName(ctx context.Context) string
- func GetQueryParam(ctx context.Context, name string) string
- func GetRequest(ctx context.Context) *http.Request
- func Mutation[I any, O any](r *Router, name string, handler func(ctx context.Context, input I) (O, error), ...)
- func NewError(code int, message string) error
- func Query[I any, O any](r *Router, name string, handler func(ctx context.Context, input I) (O, error), ...)
- func SetCookie(ctx context.Context, cookie *http.Cookie)
- func SetHeader(ctx context.Context, key, value string)
- func Subscription[I any, O any](r *Router, name string, ...)
- func WithValue(ctx context.Context, key, val interface{}) context.Context
- type CORSConfig
- type Handler
- type Logger
- type Middleware
- func APIKeyAuth(header string, ...) Middleware
- func BearerAuth(validate func(ctx context.Context, token string) (context.Context, error)) Middleware
- func LoggingMiddleware(logger Logger) Middleware
- func MaxConnectionsPerIP(limit int) Middleware
- func MaxInputSize(bytes int) Middleware
- func RateLimit(requestsPerSecond int) Middleware
- func RateLimitByKey(requestsPerSecond int, keyFunc func(ctx context.Context) string) Middleware
- func RequestID() Middleware
- func Timeout(d time.Duration) Middleware
- type Option
- type ProcedureOption
- type ProcedureType
- type Request
- type Router
- func (r *Router) Handler() http.Handler
- func (r *Router) Merge(prefix string, other *Router)
- func (r *Router) PrintRoutes(basePath string)
- func (r *Router) Procedures() map[string]*procedure
- func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request)
- func (r *Router) Use(m Middleware)
- func (r *Router) WithCORS(cfg CORSConfig)
- type SubscriptionHandler
- type SuperJSONTransformer
- type TrackedEvent
- type Transformer
- type Validator
Constants ¶
const ( ErrForbidden = trpcerrors.ErrForbidden ErrNotFound = trpcerrors.ErrNotFound ErrBadRequest = trpcerrors.ErrBadRequest )
Re-export error codes for convenience.
Variables ¶
var RequestIDKey = requestIDKeyType{}
RequestIDKey is the context key for the request ID set by the RequestID middleware.
var Version = "dev"
Version is the current version of go-trpc. It is set automatically from build info (go install / go get) or overridden via ldflags: -X github.com/sebasusnik/go-trpc/pkg/router.Version=v1.0.0
Functions ¶
func AddHeader ¶
AddHeader adds a response header value from within a procedure handler. Unlike SetHeader, this appends to existing values for the same key.
func GetBearerToken ¶
GetBearerToken extracts the bearer token from the Authorization header. Returns an empty string if the header is missing or not a Bearer token.
func GetClientIP ¶
GetClientIP extracts the client IP address from the request. It checks X-Forwarded-For, X-Real-IP, then falls back to RemoteAddr.
func GetHeaders ¶
GetHeaders returns the request headers from the context.
func GetLastEventID ¶
GetLastEventID returns the Last-Event-ID header sent by reconnecting SSE clients. Returns an empty string if the header is missing (first connection).
func GetProcedureName ¶
GetProcedureName returns the current procedure name from the context.
func GetQueryParam ¶
GetQueryParam returns a URL query parameter value, or an empty string if not found.
func GetRequest ¶
GetRequest returns the original *http.Request from the context.
func Mutation ¶
func Mutation[I any, O any](r *Router, name string, handler func(ctx context.Context, input I) (O, error), opts ...ProcedureOption)
Mutation registers a mutation procedure on the router.
func Query ¶
func Query[I any, O any](r *Router, name string, handler func(ctx context.Context, input I) (O, error), opts ...ProcedureOption)
Query registers a query procedure on the router.
func SetHeader ¶
SetHeader sets a response header from within a procedure handler. Headers must be set before the response body is written (which happens automatically after the handler returns).
func Subscription ¶
func Subscription[I any, O any](r *Router, name string, handler func(ctx context.Context, input I) (<-chan O, error), opts ...ProcedureOption)
Subscription registers a subscription procedure on the router. The handler returns a channel that yields events until closed. The channel is consumed via Server-Sent Events (SSE).
Types ¶
type CORSConfig ¶
type CORSConfig struct {
AllowedOrigins []string
AllowedMethods []string
AllowedHeaders []string
MaxAge int
}
CORSConfig holds CORS configuration.
type Logger ¶
type Logger interface {
Info(msg string, args ...any)
Debug(msg string, args ...any)
Error(msg string, args ...any)
}
Logger is the interface for logging within the router. Implementations must be safe for concurrent use.
var NopLogger Logger = nopLogger{}
NopLogger is a Logger that discards all messages. Use it with WithLogger to disable logging.
func LoggerFunc ¶
LoggerFunc adapts a single printf-style function into a Logger. All levels (Info, Debug, Error) call the same function.
type Middleware ¶
Middleware wraps a Handler, allowing pre/post processing.
func APIKeyAuth ¶
func APIKeyAuth(header string, validate func(ctx context.Context, key string) (context.Context, error)) Middleware
APIKeyAuth returns a middleware that validates an API key from a custom header. The validate function receives the key value and should return an enriched context or an error.
func BearerAuth ¶
func BearerAuth(validate func(ctx context.Context, token string) (context.Context, error)) Middleware
BearerAuth returns a middleware that validates Bearer tokens from the Authorization header. The validate function receives the token and should return an enriched context (e.g. with user info) or an error.
func LoggingMiddleware ¶
func LoggingMiddleware(logger Logger) Middleware
LoggingMiddleware returns a middleware that logs each procedure call with its name, duration, and error status.
func MaxConnectionsPerIP ¶
func MaxConnectionsPerIP(limit int) Middleware
MaxConnectionsPerIP returns a middleware that limits the number of concurrent requests from a single IP address. Useful for preventing a single client from exhausting server resources, especially with long-lived SSE subscriptions.
func MaxInputSize ¶
func MaxInputSize(bytes int) Middleware
MaxInputSize returns a middleware that rejects requests whose input payload exceeds the given byte limit. Useful for preventing oversized messages.
func RateLimit ¶
func RateLimit(requestsPerSecond int) Middleware
RateLimit returns a middleware that limits the number of requests per second across all procedures. Excess requests receive a TOO_MANY_REQUESTS error.
func RateLimitByKey ¶
func RateLimitByKey(requestsPerSecond int, keyFunc func(ctx context.Context) string) Middleware
RateLimitByKey returns a middleware that limits requests per second per key. The keyFunc extracts the rate-limiting key from the context (e.g. client IP, user ID). Inactive limiters are cleaned up periodically to prevent memory growth.
func RequestID ¶
func RequestID() Middleware
RequestID returns a middleware that generates a unique request ID for each call. The ID is stored in context (retrieve via ctx.Value(router.RequestIDKey)) and set as the X-Request-ID response header.
func Timeout ¶
func Timeout(d time.Duration) Middleware
Timeout returns a middleware that cancels procedure execution after the given duration.
type Option ¶
type Option func(*Router)
Option configures a Router.
func WithBasePath ¶
WithBasePath sets the URL prefix for the router (default: "/trpc"). The router will strip this prefix from incoming request paths.
func WithLogger ¶
WithLogger sets the logger for the router. Pass NopLogger to disable logging entirely.
func WithTransformer ¶
func WithTransformer(t Transformer) Option
WithTransformer sets the data transformer for the router. The transformer handles serialization formats like superjson. Implementations must be safe for concurrent use.
type ProcedureOption ¶
type ProcedureOption func(*procedure)
ProcedureOption configures a procedure at registration time.
func WithMiddleware ¶
func WithMiddleware(mws ...Middleware) ProcedureOption
WithMiddleware attaches middlewares to a specific procedure. These run after global middlewares set via Router.Use().
type ProcedureType ¶
type ProcedureType string
ProcedureType is the type of a tRPC procedure.
const ( ProcedureQuery ProcedureType = "query" ProcedureMutation ProcedureType = "mutation" ProcedureSubscription ProcedureType = "subscription" )
type Request ¶
type Request struct {
Input []byte
}
Request holds the raw JSON input for a procedure call.
type Router ¶
type Router struct {
// contains filtered or unexported fields
}
Router is the main tRPC router that holds procedures and middlewares.
func (*Router) PrintRoutes ¶
PrintRoutes logs all registered procedures via the router's logger.
func (*Router) Procedures ¶
Procedures returns the registered procedures (used by codegen/schema).
func (*Router) ServeHTTP ¶
func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request)
ServeHTTP implements http.Handler.
func (*Router) WithCORS ¶
func (r *Router) WithCORS(cfg CORSConfig)
WithCORS configures CORS for the router.
type SubscriptionHandler ¶
SubscriptionHandler returns a channel that yields events until closed.
type SuperJSONTransformer ¶
type SuperJSONTransformer struct{}
SuperJSONTransformer handles the superjson wire format used by @trpc/client when configured with transformer: superjson. It auto-detects whether input is in superjson format or plain JSON.
func (SuperJSONTransformer) TransformInput ¶
func (t SuperJSONTransformer) TransformInput(raw []byte) ([]byte, bool, error)
TransformInput detects the superjson envelope {"json": ..., "meta": ...} and extracts the "json" field. Plain JSON passes through unchanged.
func (SuperJSONTransformer) TransformOutput ¶
func (t SuperJSONTransformer) TransformOutput(data interface{}) (interface{}, error)
TransformOutput wraps the output data in a superjson envelope.
type TrackedEvent ¶
type TrackedEvent struct {
ID string
Data interface{}
}
TrackedEvent wraps a subscription value with a custom event ID for tracked() semantics. When a subscription handler sends a TrackedEvent on its channel, the SSE stream uses the provided ID instead of an auto-incrementing counter. This enables clients to resume from where they left off via the Last-Event-ID header on reconnect.
Usage in a handler:
ch <- router.TrackedEvent{ID: "msg-42", Data: myPayload}
type Transformer ¶
type Transformer interface {
// TransformInput checks if the raw input uses the transformer envelope format
// (e.g. {"json": ..., "meta": ...}) and extracts the plain JSON.
// Returns the plain JSON bytes, whether transformation was applied, and any error.
TransformInput(raw []byte) ([]byte, bool, error)
// TransformOutput wraps the output data in the transformer envelope format.
TransformOutput(data interface{}) (interface{}, error)
}
Transformer handles serialization/deserialization of tRPC wire formats like superjson. Implementations must be safe for concurrent use.