Documentation
¶
Index ¶
Constants ¶
This section is empty.
Variables ¶
var ( ErrInternal = New(500, "InternalError", "internal server error") ErrNotFound = New(404, "NotFound", "resource not found") ErrBind = New(400, "BindError", "request bind error") ErrInvalidArgument = New(400, "InvalidArgument", "invalid argument") ErrUnauthenticated = New(401, "Unauthenticated", "unauthenticated") ErrPermissionDenied = New(403, "PermissionDenied", "permission denied") ErrConflict = New(409, "Conflict", "resource version conflict") ErrTooManyRequests = New(429, "TooManyRequests", "too many requests, please try again later") ErrGatewayTimeout = New(504, "GatewayTimeout", "request timed out") )
Predefined errors.
Functions ¶
func RegisterMapper
deprecated
func RegisterMapper(m ErrorMapper)
RegisterMapper registers a global error mapper. Typically called during the application startup phase (e.g. inside the Setup callback). Panics if m is nil.
Deprecated: Global mappers are shared across all App instances, making parallel tests and multi-App scenarios unsafe. Prefer per-App scoped mappers via chok.WithErrorMapper(m), which uses MapperRegistry under the hood and is resolved first by ResolveWithContext.
Thread-safe: protected by a read-write mutex. Resolve acquires a read lock, so concurrent requests are not blocked by each other.
func ResetMappersForTest ¶
func ResetMappersForTest()
ResetMappersForTest clears all registered mappers. Exported for cross-package test cleanup only — do not use in production code.
func WithMapperRegistry ¶
func WithMapperRegistry(ctx context.Context, r *MapperRegistry) context.Context
WithMapperRegistry stores a MapperRegistry in ctx. The handler layer checks this before falling through to the global Resolve.
Types ¶
type Error ¶
type Error struct {
Code int `json:"code"`
Reason string `json:"reason"`
Message string `json:"message"`
Metadata map[string]any `json:"metadata,omitempty"`
// Headers holds response headers the caller must emit alongside the
// body — e.g. Retry-After for 429/503. Responders set these via
// WithHeader. Not serialized into JSON.
Headers map[string]string `json:"-"`
// contains filtered or unexported fields
}
func FromError ¶
FromError converts any error to *Error. Unwraps via errors.As; non-*Error defaults to 500 InternalError with the original error attached as the Wrap cause so errors.Unwrap and structured logging still reach the root. The user-facing Message stays the generic "internal server error" so internal detail is not leaked into the response body.
func ResolveWithContext ¶
ResolveWithContext checks the context-scoped registry first, then falls through to the global mappers. This is the preferred entry point for the handler layer.
func (*Error) Is ¶
Is matches by Code+Reason, ignoring Message/Metadata. This allows WithMessage()/WithMetadata() copies to match the original sentinel.
func (*Error) WithHeader ¶
WithHeader returns a copy with an additional response header. Typical use: apierr.ErrTooManyRequests.WithHeader("Retry-After", "30"). The responder writes these headers before emitting the JSON body.
func (*Error) WithMessage ¶
WithMessage returns a copy with a different message.
func (*Error) WithMetadata ¶
WithMetadata returns a copy with an additional metadata key.
func (*Error) Wrap ¶
Wrap returns a copy with the given cause attached for error-chain traversal. The cause is not serialized into JSON responses (security: internal errors are not leaked). Use errors.Unwrap or %w logging to inspect the chain.
Implementation note: WithMessage/WithMetadata use `cp := *e` (shallow copy), which automatically preserves cause. If those methods are ever refactored to explicit field assignment, cause must be copied too.
type ErrorMapper ¶
ErrorMapper maps a non-*Error to an *Error. Returns nil if unrecognized.
type MapperRegistry ¶
type MapperRegistry struct {
// contains filtered or unexported fields
}
MapperRegistry holds a set of ErrorMappers scoped to an application instance. Unlike the global RegisterMapper, MapperRegistry is safe for parallel tests and multi-App scenarios — each App gets its own registry that doesn't interfere with other instances.
func MapperRegistryFrom ¶
func MapperRegistryFrom(ctx context.Context) *MapperRegistry
MapperRegistryFrom retrieves the MapperRegistry from ctx, or nil.
func NewMapperRegistry ¶
func NewMapperRegistry() *MapperRegistry
NewMapperRegistry creates an empty MapperRegistry.
func (*MapperRegistry) Register ¶
func (r *MapperRegistry) Register(m ErrorMapper)
Register adds a mapper to this registry. Thread-safe.
func (*MapperRegistry) Resolve ¶
func (r *MapperRegistry) Resolve(err error) *Error
Resolve tries all mappers in this registry. Returns nil if no mapper matches.