Documentation
¶
Index ¶
- func HTTPStatusFromCode(code ErrorCode) int
- func MethodFromContext(ctx context.Context) (service, method string, ok bool)
- func NewTestContext(ctx context.Context, w http.ResponseWriter, r *http.Request, info *RPCInfo) context.Context
- func RequestFromContext(ctx context.Context) *http.Request
- func SetHeader(ctx context.Context, key, value string)
- func TestContextSetup() ...
- type CacheConfig
- type Empty
- type Error
- func AlreadyExists(message string, details ...map[string]any) *Error
- func Conflict(message string, details ...map[string]any) *Error
- func DeadlineExceeded(message string, details ...map[string]any) *Error
- func DefaultErrorTransformer(err error) *Error
- func Errorf(code ErrorCode, format string, args ...any) *Error
- func Gone(message string, details ...map[string]any) *Error
- func Internal(message string, details ...map[string]any) *Error
- func InvalidArgument(message string, details ...map[string]any) *Error
- func NewError(code ErrorCode, message string) *Error
- func NotFound(message string, details ...map[string]any) *Error
- func NotImplemented(message string, details ...map[string]any) *Error
- func PermissionDenied(message string, details ...map[string]any) *Error
- func ResourceExhausted(message string, details ...map[string]any) *Error
- func Unauthenticated(message string, details ...map[string]any) *Error
- func Unavailable(message string, details ...map[string]any) *Error
- type ErrorCode
- type ErrorTransformer
- type ExportedRoute
- type HandlerConfig
- type HandlerFunc
- type RPCInfo
- type RPCMethod
- type Registry
- func (r *Registry) ExportRoutes() map[string]ExportedRoute
- func (r *Registry) Handler() http.Handler
- func (r *Registry) ServeHTTP(w http.ResponseWriter, req *http.Request)
- func (r *Registry) Service(name string) *Service
- func (r *Registry) WithErrorTransformer(fn ErrorTransformer) *Registry
- func (r *Registry) WithLogger(logger *slog.Logger) *Registry
- func (r *Registry) WithMaskInternalErrors() *Registry
- func (r *Registry) WithMaxRequestBodySize(size uint64) *Registry
- func (r *Registry) WithMiddleware(mw func(http.Handler) http.Handler) *Registry
- func (r *Registry) WithUnaryInterceptor(i UnaryInterceptor) *Registry
- type Service
- type UnaryGetHandler
- func (h *UnaryGetHandler[Req, Res]) CacheControl(cfg CacheConfig) *UnaryGetHandler[Req, Res]
- func (h *UnaryGetHandler[Req, Res]) Metadata() *meta.MethodMetadata
- func (h *UnaryGetHandler[Req, Res]) ServeHTTP(w http.ResponseWriter, r *http.Request, config HandlerConfig)
- func (h *UnaryGetHandler[Req, Res]) WithSkipValidation() *UnaryGetHandler[Req, Res]
- func (h *UnaryGetHandler[Req, Res]) WithStrictQueryParams() *UnaryGetHandler[Req, Res]
- func (h *UnaryGetHandler[Req, Res]) WithUnaryInterceptor(i UnaryInterceptor) *UnaryGetHandler[Req, Res]
- type UnaryHandler
- type UnaryInterceptor
- type UnaryPostHandler
- func (h *UnaryPostHandler[Req, Res]) Metadata() *meta.MethodMetadata
- func (h *UnaryPostHandler[Req, Res]) ServeHTTP(w http.ResponseWriter, r *http.Request, config HandlerConfig)
- func (h *UnaryPostHandler[Req, Res]) WithMaxRequestBodySize(size uint64) *UnaryPostHandler[Req, Res]
- func (h *UnaryPostHandler[Req, Res]) WithSkipValidation() *UnaryPostHandler[Req, Res]
- func (h *UnaryPostHandler[Req, Res]) WithUnaryInterceptor(i UnaryInterceptor) *UnaryPostHandler[Req, Res]
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func HTTPStatusFromCode ¶
HTTPStatusFromCode maps an ErrorCode to an HTTP status code.
func MethodFromContext ¶
MethodFromContext returns the service and method name of the current RPC.
func NewTestContext ¶
func NewTestContext(ctx context.Context, w http.ResponseWriter, r *http.Request, info *RPCInfo) context.Context
NewTestContext creates a context with RPC metadata for testing. This is useful when testing handlers directly without going through the Registry.
Example:
req := httptest.NewRequest("POST", "/test", body)
w := httptest.NewRecorder()
info := &RPCInfo{Service: "MyService", Method: "MyMethod"}
ctx := NewTestContext(req.Context(), w, req, info)
req = req.WithContext(ctx)
func RequestFromContext ¶
RequestFromContext returns the HTTP request from the context.
func SetHeader ¶
SetHeader sets an HTTP response header. It requires that the handler was called via the Registry.
func TestContextSetup ¶
func TestContextSetup() func(ctx context.Context, w http.ResponseWriter, r *http.Request, service, method string) context.Context
TestContextSetup returns a context setup function for use with testutil.NewRequest(). This provides a convenient way to set up tygor RPC context when testing from external packages.
Example usage:
req, w := testutil.NewRequest(tygor.TestContextSetup()).
POST("/test").
WithJSON(&MyRequest{...}).
Build()
handler.ServeHTTP(w, req, tygor.HandlerConfig{})
Types ¶
type CacheConfig ¶
type CacheConfig struct {
// MaxAge specifies the maximum time a resource is considered fresh (RFC 9111 Section 5.2.2.1).
// After this time, caches must revalidate before serving the cached response.
MaxAge time.Duration
// SMaxAge is like MaxAge but only applies to shared caches like CDNs (RFC 9111 Section 5.2.2.10).
// Overrides MaxAge for shared caches. Private caches ignore this directive.
SMaxAge time.Duration
// StaleWhileRevalidate allows serving stale content while revalidating in the background (RFC 5861).
// Example: MaxAge=60s, StaleWhileRevalidate=300s means serve from cache for 60s,
// then serve stale content for up to 300s more while fetching fresh data in background.
StaleWhileRevalidate time.Duration
// StaleIfError allows serving stale content if the origin server is unavailable (RFC 5861).
// Example: StaleIfError=86400 allows serving day-old stale content if origin returns 5xx errors.
StaleIfError time.Duration
// Public indicates the response may be cached by any cache, including CDNs (RFC 9111 Section 5.2.2.9).
// Default is false (private), meaning only the user's browser cache may store it.
// Set to true for responses that are safe to cache publicly.
Public bool
// MustRevalidate requires caches to revalidate stale responses with the origin before serving (RFC 9111 Section 5.2.2.2).
// Prevents serving stale content. Useful when stale data could cause problems.
MustRevalidate bool
// Immutable indicates the response will never change during its freshness lifetime (RFC 8246).
// Browsers won't send conditional requests for immutable resources within MaxAge period.
// Useful for content-addressed assets like "bundle.abc123.js".
Immutable bool
}
CacheConfig defines HTTP cache directives for GET requests. See RFC 9111 (HTTP Caching) for detailed semantics.
Common patterns:
- Simple caching: CacheConfig{MaxAge: 5*time.Minute}
- Public CDN caching: CacheConfig{MaxAge: 5*time.Minute, Public: true}
- Stale-while-revalidate: CacheConfig{MaxAge: 1*time.Minute, StaleWhileRevalidate: 5*time.Minute}
- Immutable assets: CacheConfig{MaxAge: 365*24*time.Hour, Immutable: true}
type Empty ¶
type Empty *struct{}
Empty represents a void request or response. Use this for operations that don't return meaningful data. The zero value is nil, which serializes to JSON null.
Example:
func DeleteUser(ctx context.Context, req *DeleteUserRequest) (tygor.Empty, error) {
// ... delete user
return nil, nil
}
Wire format: {"result": null}
type Error ¶
type Error struct {
Code ErrorCode `json:"code"`
Message string `json:"message"`
Details map[string]any `json:"details,omitempty"`
}
Error is the standard JSON error envelope.
func AlreadyExists ¶ added in v0.5.0
AlreadyExists creates an already_exists error (409).
func DeadlineExceeded ¶ added in v0.5.0
DeadlineExceeded creates a deadline_exceeded error (504).
func DefaultErrorTransformer ¶
DefaultErrorTransformer maps standard Go errors to RPC errors.
func InvalidArgument ¶ added in v0.5.0
InvalidArgument creates an invalid_argument error (400).
func NotImplemented ¶ added in v0.5.0
NotImplemented creates a not_implemented error (501).
func PermissionDenied ¶ added in v0.5.0
PermissionDenied creates a permission_denied error (403).
func ResourceExhausted ¶ added in v0.5.0
ResourceExhausted creates a resource_exhausted error (429).
func Unauthenticated ¶ added in v0.5.0
Unauthenticated creates an unauthenticated error (401).
func Unavailable ¶ added in v0.5.0
Unavailable creates an unavailable error (503).
type ErrorCode ¶
type ErrorCode string
ErrorCode represents a machine-readable error code.
const ( CodeInvalidArgument ErrorCode = "invalid_argument" CodeUnauthenticated ErrorCode = "unauthenticated" CodePermissionDenied ErrorCode = "permission_denied" CodeNotFound ErrorCode = "not_found" CodeMethodNotAllowed ErrorCode = "method_not_allowed" CodeConflict ErrorCode = "conflict" CodeAlreadyExists ErrorCode = "already_exists" // Alias for conflict, used when resource already exists CodeGone ErrorCode = "gone" CodeResourceExhausted ErrorCode = "resource_exhausted" CodeCanceled ErrorCode = "canceled" CodeInternal ErrorCode = "internal" CodeNotImplemented ErrorCode = "not_implemented" CodeDeadlineExceeded ErrorCode = "deadline_exceeded" )
type ErrorTransformer ¶
ErrorTransformer is a function that maps an application error to an RPC error. If it returns nil, the default transformer logic should be applied.
type ExportedRoute ¶
ExportedRoute contains metadata about a registered route for code generation.
type HandlerConfig ¶
type HandlerConfig struct {
ErrorTransformer ErrorTransformer
MaskInternalErrors bool
Interceptors []UnaryInterceptor
Logger *slog.Logger
MaxRequestBodySize uint64
}
HandlerConfig contains configuration passed from Registry to handlers.
type HandlerFunc ¶
HandlerFunc represents the next handler in the chain.
type RPCMethod ¶
type RPCMethod interface {
ServeHTTP(w http.ResponseWriter, r *http.Request, config HandlerConfig)
Metadata() *meta.MethodMetadata
}
RPCMethod is the interface for registered handlers. It is exported so users can pass it to Register, but sealed so they cannot implement it.
type Registry ¶
type Registry struct {
// contains filtered or unexported fields
}
func NewRegistry ¶
func NewRegistry() *Registry
func (*Registry) ExportRoutes ¶
func (r *Registry) ExportRoutes() map[string]ExportedRoute
ExportRoutes returns all registered routes for code generation purposes. This is used by the generator package.
func (*Registry) Handler ¶
Handler returns the registry wrapped with all configured middleware. The middleware is applied in the order it was added via WithMiddleware.
func (*Registry) ServeHTTP ¶
func (r *Registry) ServeHTTP(w http.ResponseWriter, req *http.Request)
ServeHTTP implements http.Handler.
func (*Registry) WithErrorTransformer ¶
func (r *Registry) WithErrorTransformer(fn ErrorTransformer) *Registry
WithErrorTransformer adds a custom error transformer. It returns the registry for chaining.
func (*Registry) WithLogger ¶
WithLogger sets a custom logger for the registry. If not set, slog.Default() will be used.
func (*Registry) WithMaskInternalErrors ¶
WithMaskInternalErrors enables masking of internal error messages. This is useful in production to avoid leaking sensitive information. The original error is still available to interceptors and logging.
func (*Registry) WithMaxRequestBodySize ¶
WithMaxRequestBodySize sets the default maximum request body size for all handlers. Individual handlers can override this with Handler.WithMaxRequestBodySize. A value of 0 means no limit. Default is 1MB (1 << 20).
func (*Registry) WithMiddleware ¶
WithMiddleware adds an HTTP middleware to wrap the registry. Middleware is applied in the order added (first added is outermost). Use Handler() to get the wrapped handler.
func (*Registry) WithUnaryInterceptor ¶
func (r *Registry) WithUnaryInterceptor(i UnaryInterceptor) *Registry
WithUnaryInterceptor adds a global interceptor. Global interceptors are executed before service-level and handler-level interceptors.
Interceptor execution order:
- Global interceptors (added via Registry.WithUnaryInterceptor)
- Service interceptors (added via Service.WithUnaryInterceptor)
- Handler interceptors (added via Handler.WithUnaryInterceptor)
- Handler function
Within each level, interceptors execute in the order they were added.
type Service ¶
type Service struct {
// contains filtered or unexported fields
}
func (*Service) Register ¶
Register registers a handler for the given operation name. If a handler is already registered for this service and method, it will be replaced and a warning will be logged.
func (*Service) WithUnaryInterceptor ¶
func (s *Service) WithUnaryInterceptor(i UnaryInterceptor) *Service
WithUnaryInterceptor adds an interceptor to this service. Service interceptors execute after global interceptors but before handler interceptors. See Registry.WithUnaryInterceptor for the complete execution order.
type UnaryGetHandler ¶ added in v0.5.0
type UnaryGetHandler[Req any, Res any] struct { UnaryHandler[Req, Res] // contains filtered or unexported fields }
UnaryGetHandler implements RPCMethod for GET requests (cacheable read operations).
It embeds UnaryHandler, inheriting methods like WithUnaryInterceptor and WithSkipValidation.
Request Type Guidelines:
- Use struct types for simple cases, pointer types when you need optional fields
- Request parameters are decoded from URL query string
Struct vs Pointer Types:
- Struct types (e.g., ListParams): Query parameters are decoded directly into the struct
- Pointer types (e.g., *ListParams): A new instance is created and query parameters are decoded into it
Example:
func ListPosts(ctx context.Context, req ListPostsParams) ([]*Post, error) { ... }
UnaryGet(ListPosts).CacheControl(tygor.CacheConfig{
MaxAge: 5 * time.Minute,
Public: true,
})
func UnaryGet ¶
func UnaryGet[Req any, Res any](fn func(context.Context, Req) (Res, error)) *UnaryGetHandler[Req, Res]
UnaryGet creates a new GET handler from a generic function for cacheable read operations.
The handler function signature is func(context.Context, Req) (Res, error). Requests are decoded from URL query parameters.
Use CacheControl() to configure HTTP caching behavior.
The returned UnaryGetHandler supports:
- WithUnaryInterceptor (from UnaryHandler)
- WithSkipValidation (from UnaryHandler)
- CacheControl (specific to GET)
- WithStrictQueryParams (specific to GET)
func (*UnaryGetHandler[Req, Res]) CacheControl ¶ added in v0.5.0
func (h *UnaryGetHandler[Req, Res]) CacheControl(cfg CacheConfig) *UnaryGetHandler[Req, Res]
CacheControl sets detailed HTTP cache directives for the handler. See CacheConfig documentation and RFC 9111 for directive semantics.
Example:
UnaryGet(ListPosts).CacheControl(tygor.CacheConfig{
MaxAge: 5 * time.Minute,
StaleWhileRevalidate: 1 * time.Minute,
Public: true,
}).WithUnaryInterceptor(...)
// Sets: Cache-Control: public, max-age=300, stale-while-revalidate=60
func (*UnaryGetHandler[Req, Res]) Metadata ¶ added in v0.5.0
func (h *UnaryGetHandler[Req, Res]) Metadata() *meta.MethodMetadata
Metadata returns the runtime metadata for the GET handler.
func (*UnaryGetHandler[Req, Res]) ServeHTTP ¶ added in v0.5.0
func (h *UnaryGetHandler[Req, Res]) ServeHTTP(w http.ResponseWriter, r *http.Request, config HandlerConfig)
ServeHTTP implements the RPC handler for GET requests with caching support.
func (*UnaryGetHandler[Req, Res]) WithSkipValidation ¶ added in v0.5.0
func (h *UnaryGetHandler[Req, Res]) WithSkipValidation() *UnaryGetHandler[Req, Res]
WithSkipValidation disables validation for this handler. By default, all handlers validate requests using the validator package. Use this when you need to handle validation manually or when the request type has no validation tags.
func (*UnaryGetHandler[Req, Res]) WithStrictQueryParams ¶ added in v0.5.0
func (h *UnaryGetHandler[Req, Res]) WithStrictQueryParams() *UnaryGetHandler[Req, Res]
WithStrictQueryParams enables strict query parameter validation for GET requests. By default, unknown query parameters are ignored (lenient mode). When enabled, requests with unknown query parameters will return an error. This helps catch typos and enforces exact parameter expectations.
func (*UnaryGetHandler[Req, Res]) WithUnaryInterceptor ¶ added in v0.5.0
func (h *UnaryGetHandler[Req, Res]) WithUnaryInterceptor(i UnaryInterceptor) *UnaryGetHandler[Req, Res]
WithUnaryInterceptor adds an interceptor to this handler. Handler interceptors execute after global and service interceptors. See Registry.WithUnaryInterceptor for the complete execution order.
type UnaryHandler ¶ added in v0.5.0
UnaryHandler contains common configuration for all unary handlers.
This is a base type. See UnaryPostHandler and UnaryGetHandler for specific implementations.
func (*UnaryHandler[Req, Res]) Metadata ¶ added in v0.5.0
func (h *UnaryHandler[Req, Res]) Metadata() *meta.MethodMetadata
Metadata returns the runtime metadata for the handler.
type UnaryInterceptor ¶
type UnaryInterceptor func(ctx context.Context, req any, info *RPCInfo, handler HandlerFunc) (res any, err error)
UnaryInterceptor is a generic hook that wraps the RPC handler execution for unary (non-streaming) calls. req/res are pointers to the structs.
type UnaryPostHandler ¶ added in v0.5.0
type UnaryPostHandler[Req any, Res any] struct { UnaryHandler[Req, Res] // contains filtered or unexported fields }
UnaryPostHandler implements RPCMethod for POST requests (state-changing operations).
It embeds UnaryHandler, inheriting methods like WithUnaryInterceptor and WithSkipValidation.
Request Type Guidelines:
- Use struct or pointer types
- Request is decoded from JSON body
Example:
func CreateUser(ctx context.Context, req *CreateUserRequest) (*User, error) { ... }
Unary(CreateUser)
func UpdatePost(ctx context.Context, req *UpdatePostRequest) (*Post, error) { ... }
Unary(UpdatePost).WithUnaryInterceptor(requireAuth)
func Unary ¶
func Unary[Req any, Res any](fn func(context.Context, Req) (Res, error)) *UnaryPostHandler[Req, Res]
Unary creates a new POST handler from a generic function for unary (non-streaming) RPCs.
The handler function signature is func(context.Context, Req) (Res, error). Requests are decoded from JSON body.
For GET requests (cacheable reads), use UnaryGet instead.
The returned UnaryPostHandler supports:
- WithUnaryInterceptor (from UnaryHandler)
- WithSkipValidation (from UnaryHandler)
- WithMaxRequestBodySize (specific to POST)
func (*UnaryPostHandler[Req, Res]) Metadata ¶ added in v0.5.0
func (h *UnaryPostHandler[Req, Res]) Metadata() *meta.MethodMetadata
Metadata returns the runtime metadata for the POST handler.
func (*UnaryPostHandler[Req, Res]) ServeHTTP ¶ added in v0.5.0
func (h *UnaryPostHandler[Req, Res]) ServeHTTP(w http.ResponseWriter, r *http.Request, config HandlerConfig)
ServeHTTP implements the RPC handler for POST requests.
func (*UnaryPostHandler[Req, Res]) WithMaxRequestBodySize ¶ added in v0.5.0
func (h *UnaryPostHandler[Req, Res]) WithMaxRequestBodySize(size uint64) *UnaryPostHandler[Req, Res]
WithMaxRequestBodySize sets the maximum request body size for this handler. This overrides the registry-level default. A value of 0 means no limit.
func (*UnaryPostHandler[Req, Res]) WithSkipValidation ¶ added in v0.5.0
func (h *UnaryPostHandler[Req, Res]) WithSkipValidation() *UnaryPostHandler[Req, Res]
WithSkipValidation disables validation for this handler. By default, all handlers validate requests using the validator package. Use this when you need to handle validation manually or when the request type has no validation tags.
func (*UnaryPostHandler[Req, Res]) WithUnaryInterceptor ¶ added in v0.5.0
func (h *UnaryPostHandler[Req, Res]) WithUnaryInterceptor(i UnaryInterceptor) *UnaryPostHandler[Req, Res]
WithUnaryInterceptor adds an interceptor to this handler. Handler interceptors execute after global and service interceptors. See Registry.WithUnaryInterceptor for the complete execution order.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
examples
module
|
|
|
blog
command
|
|
|
newsserver
command
|
|
|
internal
|
|
|
Package testutil provides testing helpers for HTTP handlers and tygor RPC handlers.
|
Package testutil provides testing helpers for HTTP handlers and tygor RPC handlers. |