Documentation
¶
Overview ¶
Package contract defines Gombit's Huma DTO conventions, the D10 success and error envelopes, and draft §41 application error category mapping.
Public API routes are Huma-typed handlers. Request and response shapes come from Go structs and Huma validation tags — there is no bespoke Bind layer.
Success:
{"data": ...}
{"data": ..., "meta": {"page": 1, "per_page": 20, "total": 125}}
Use contract.DataMeta[T, PageMeta] (or another concrete meta type) so OpenAPI emits a real meta schema. Generated list handlers honor page/per_page via ClampPage (default page 1, per_page 20, max 100). Validation failures (Huma Install path):
{"error":{"code":"validation_error","message":"...","fields":{...},"request_id":"..."}}
Application errors (return contract.NotFound / New / ... via WithContext):
{"error":{"code":"not_found","message":"...","request_id":"..."}}
OpenAPI 3.1 is served at /openapi.json. Interactive docs are at /docs when enabled. Use OpenAPIJSON / WriteOpenAPI to persist the live spec.
See docs/contract.md and docs/openapi.md.
Index ¶
- Constants
- func ClampPage(page, perPage int) (int, int)
- func CodeFor(cat Category) string
- func FieldsFromErrors(errs ...error) map[string][]string
- func HumaConfig(title, version string) huma.Config
- func HumaConfigFor(title, version string, docsEnabled bool) huma.Config
- func Install(opts InstallOptions)
- func OpenAPIJSON(api huma.API) ([]byte, error)
- func PageOffset(page, perPage int) int
- func StatusFor(cat Category) int
- func WriteOpenAPI(path string, api huma.API) error
- func WriteOpenAPIFile(path string, spec []byte) error
- type Category
- type Data
- type DataMeta
- type ErrorBody
- type ErrorEnvelope
- func Authentication(message string) *ErrorEnvelope
- func Authorization(message string) *ErrorEnvelope
- func Conflict(message string) *ErrorEnvelope
- func DependencyUnavailable(message string) *ErrorEnvelope
- func Internal(message string) *ErrorEnvelope
- func New(cat Category, message string) *ErrorEnvelope
- func NotFound(message string) *ErrorEnvelope
- func PayloadTooLarge(message string) *ErrorEnvelope
- func RateLimited(message string) *ErrorEnvelope
- func Validation(message string, fields map[string][]string) *ErrorEnvelope
- func WithContext(ctx context.Context, err *ErrorEnvelope) *ErrorEnvelope
- type InstallOptions
- type PageMeta
Constants ¶
const ( // DefaultPage is the 1-based page used when page is missing or < 1. DefaultPage = 1 // DefaultPerPage is the page size used when per_page is missing or < 1. DefaultPerPage = 20 // MaxPerPage is the upper clamp for per_page (admin and generated lists). MaxPerPage = 100 )
const ( // OpenAPIPath is the Huma OpenAPI prefix. Clients fetch /openapi.json. OpenAPIPath = "/openapi" // DocsPath is the FastAPI-style interactive docs UI. DocsPath = "/docs" )
const CodePayloadTooLarge = "payload_too_large"
CodePayloadTooLarge is the D10 code for a body that exceeded a framework buffer cap (HTTP 413). This is not a §41 category.
const CodeValidationError = "validation_error"
CodeValidationError is the stable D10 code for request validation failures.
Variables ¶
This section is empty.
Functions ¶
func ClampPage ¶ added in v0.1.3
ClampPage returns a 1-based page and a per-page size using the v0.1 defaults. Values less than 1 become DefaultPage / DefaultPerPage; per_page above MaxPerPage is clamped to MaxPerPage.
func CodeFor ¶
CodeFor returns the stable D10 error.code for a category. Validation keeps the M3-1 / D10 name "validation_error"; other categories use the category string. Unknown categories map to "internal".
func FieldsFromErrors ¶
FieldsFromErrors maps Huma validation detail errors into D10 field errors.
Body locations lose the leading "body." prefix so JSON field names match the request body. Query, path, and header locations keep their prefixes.
func HumaConfig ¶
HumaConfig returns the default Huma configuration for a Gombit app.
Interactive docs are enabled at /docs (Swagger UI). The schema browser stays disabled. Pass docsEnabled=false to omit the docs route (production default).
func HumaConfigFor ¶
HumaConfigFor returns Huma configuration with docs explicitly enabled or not.
func Install ¶
func Install(opts InstallOptions)
Install replaces Huma's default RFC 9457 Problem Details errors with the D10 envelope. It is safe to call more than once; only the first call applies.
Install only classifies errors built through Huma's NewError hooks (request validation). Application errors from New / NotFound / etc. set status and code via StatusFor / CodeFor and are not reclassified.
func OpenAPIJSON ¶
OpenAPIJSON marshals the Huma-generated OpenAPI 3.1 document.
func PageOffset ¶ added in v0.1.3
PageOffset returns the 0-based OFFSET for a 1-based page and per-page size. Callers should pass values already returned by ClampPage.
func StatusFor ¶
StatusFor returns the HTTP status for a §41 category. Unknown categories map to 500 Internal Server Error.
func WriteOpenAPI ¶
WriteOpenAPI writes the Huma-generated OpenAPI document to path.
func WriteOpenAPIFile ¶
WriteOpenAPIFile writes a pre-marshaled OpenAPI document to path.
Types ¶
type Category ¶
type Category string
Category is a draft §41 framework error category. Transport adapters map categories to HTTP status codes via StatusFor; they do not leak into service layer return types as raw status integers.
const ( CategoryValidation Category = "validation" CategoryAuthentication Category = "authentication" CategoryAuthorization Category = "authorization" CategoryNotFound Category = "not_found" CategoryConflict Category = "conflict" CategoryRateLimited Category = "rate_limited" CategoryInternal Category = "internal" )
type Data ¶
type Data[T any] struct { Data T `json:"data"` }
Data is the D10 success envelope without meta: {"data": ...}.
type DataMeta ¶
DataMeta is the D10 success envelope with typed meta: {"data": ..., "meta": ...}.
Use a concrete meta type so OpenAPI emits a real schema (not empty object). Prefer a pointer meta value so omitempty drops absent meta:
contract.DataMeta[[]Widget, PageMeta]{Data: items, Meta: &contract.PageMeta{...}}
A non-nil zero PageMeta still serializes (omitempty does not treat structs as empty).
type ErrorBody ¶
type ErrorBody struct {
Code string `json:"code"`
Message string `json:"message"`
Fields map[string][]string `json:"fields,omitempty"`
RequestID string `json:"request_id,omitempty"`
}
ErrorBody is the D10 error object nested under "error".
type ErrorEnvelope ¶
type ErrorEnvelope struct {
Body ErrorBody `json:"error"`
// contains filtered or unexported fields
}
ErrorEnvelope is the D10 error response body and a huma.StatusError.
It intentionally does not implement huma.ContentTypeFilter so responses keep Content-Type application/json instead of application/problem+json.
func Authentication ¶
func Authentication(message string) *ErrorEnvelope
Authentication returns an authentication category error (HTTP 401). Wrap with WithContext in handlers to attach request_id.
func Authorization ¶
func Authorization(message string) *ErrorEnvelope
Authorization returns an authorization category error (HTTP 403). Wrap with WithContext in handlers to attach request_id.
func Conflict ¶
func Conflict(message string) *ErrorEnvelope
Conflict returns a conflict category error (HTTP 409). Wrap with WithContext in handlers to attach request_id.
func DependencyUnavailable ¶
func DependencyUnavailable(message string) *ErrorEnvelope
DependencyUnavailable returns a dependency_unavailable error (HTTP 503). Wrap with WithContext in handlers to attach request_id.
func Internal ¶
func Internal(message string) *ErrorEnvelope
Internal returns an internal category error (HTTP 500). Wrap with WithContext in handlers to attach request_id.
func New ¶
func New(cat Category, message string) *ErrorEnvelope
New builds a D10 ErrorEnvelope from a §41 category and message.
Callers should wrap with WithContext so request_id is populated:
return nil, contract.WithContext(ctx, contract.New(contract.CategoryNotFound, "missing"))
func NotFound ¶
func NotFound(message string) *ErrorEnvelope
NotFound returns a not_found category error (HTTP 404). Wrap with WithContext in handlers to attach request_id.
func PayloadTooLarge ¶ added in v0.1.3
func PayloadTooLarge(message string) *ErrorEnvelope
PayloadTooLarge returns a D10 error for a request body that exceeded a framework buffer cap (HTTP 413). This is not a §41 category; the sanitizer bound is not the deferred body-size middleware.
func RateLimited ¶
func RateLimited(message string) *ErrorEnvelope
RateLimited returns a rate_limited category error (HTTP 429). Wrap with WithContext in handlers to attach request_id.
func Validation ¶
func Validation(message string, fields map[string][]string) *ErrorEnvelope
Validation returns a validation category error (HTTP 422, code validation_error). Wrap with WithContext in handlers to attach request_id.
func WithContext ¶
func WithContext(ctx context.Context, err *ErrorEnvelope) *ErrorEnvelope
WithContext returns err with request_id filled from Install's RequestID reader when available. Application handlers should wrap category errors:
return nil, contract.WithContext(ctx, contract.NotFound("missing"))
func (*ErrorEnvelope) Error ¶
func (e *ErrorEnvelope) Error() string
Error satisfies the error interface.
func (*ErrorEnvelope) GetStatus ¶
func (e *ErrorEnvelope) GetStatus() int
GetStatus returns the HTTP status for this error.
func (*ErrorEnvelope) WithFields ¶
func (e *ErrorEnvelope) WithFields(fields map[string][]string) *ErrorEnvelope
WithFields returns a shallow copy with D10 fields set. The error code stays the category code (not forced to validation_error).
func (*ErrorEnvelope) WithRequestID ¶
func (e *ErrorEnvelope) WithRequestID(requestID string) *ErrorEnvelope
WithRequestID returns a shallow copy with request_id set (for tests/helpers).
type InstallOptions ¶
type InstallOptions struct {
// RequestID reads the active request ID from a request context.
RequestID func(context.Context) string
}
InstallOptions configures Huma error installation.
type PageMeta ¶
type PageMeta struct {
Page int `json:"page"`
PerPage int `json:"per_page"`
Total int64 `json:"total"`
}
PageMeta is the conventional pagination meta object for collection responses. It is the v0.1 typed default for list endpoints; other meta shapes can use the second type parameter on DataMeta when needed.
Generated list handlers and the admin data plane honor page/per_page with ClampPage defaults: page 1, per_page 20, max 100. Meta.Total is the matching row count, not len(data).