Documentation
¶
Overview ¶
Package actions is a typed HTTP action framework with OpenAPI 3.1 generation for chi. You declare a route once as a typed Action[Req, Resp] and a Registry turns it into an http.HandlerFunc (decode → validate → handle → encode), a JSON Schema 2020-12, an OpenAPI 3.1 document (JSON and YAML), and a browsable HTML/Markdown index — all derived from the same reflected types, so the published contract cannot drift from runtime behavior.
The core depends only on the standard library, github.com/go-chi/chi/v5, github.com/google/uuid, and gopkg.in/yaml.v3. It carries no domain types: error mapping is pluggable via ErrorMapper (see WithErrorMapper) and the OpenAPI info block is caller-configurable (see WithInfo).
Index ¶
- Constants
- func Register[Req, Resp any](reg *Registry, a Action[Req, Resp])
- func RequestIDFromContext(ctx context.Context) string
- type APIError
- type Accepted
- type Action
- type Created
- type Empty
- type ErrorMapper
- type FieldError
- type List
- type ListMeta
- type Middleware
- type Observation
- type ObserveFunc
- type Option
- func WithErrorMapper(m ErrorMapper) Option
- func WithInfo(title, description, version string) Option
- func WithMaxBodyBytes(n int64) Option
- func WithMethodNotAllowedHandler(h http.Handler) Option
- func WithMiddleware(mw ...Middleware) Option
- func WithNotFoundHandler(h http.Handler) Option
- func WithObserver(fn ObserveFunc) Option
- func WithOpenAPIVersion(v string) Option
- func WithRequestIDGenerator(gen func() string) Option
- func WithSecurity(reqs ...SecurityRequirement) Option
- func WithSecurityScheme(name string, scheme SecurityScheme) Option
- func WithServers(servers ...Server) Option
- func WithStripPrefix(prefix string) Option
- type Page
- type Registry
- type Response
- type SecurityRequirement
- type SecurityScheme
- type Server
- type StatusDoc
- type Validatable
Constants ¶
const ( CodeValidation = "VALIDATION_ERROR" CodeBadRequest = "BAD_REQUEST" CodeForbidden = "FORBIDDEN" CodeNotFound = "NOT_FOUND" CodeConflict = "CONFLICT" CodePayloadTooLarge = "PAYLOAD_TOO_LARGE" CodeTooManyRequests = "TOO_MANY_REQUESTS" CodeInternal = "INTERNAL_ERROR" CodeMethodNotAllowed = "METHOD_NOT_ALLOWED" CodeTimeout = "TIMEOUT" )
Stable, transport-level error codes. These are generic HTTP error codes with no domain coupling; a custom ErrorMapper may emit any code it likes. The framework itself emits only CodeValidation, CodeBadRequest, CodeNotFound, CodeInternal, CodeMethodNotAllowed, CodePayloadTooLarge, and CodeTimeout; the remaining codes are provided as a stable vocabulary for ErrorMappers and handlers so services across the ecosystem agree on the wire spelling.
Variables ¶
This section is empty.
Functions ¶
func Register ¶
Register is the only typed seam. It builds the http.HandlerFunc (decode → validate → Handle → encode) and stores it keyed by ID. It panics if the registry is already frozen.
func RequestIDFromContext ¶
RequestIDFromContext returns the request correlation id placed in ctx by the framework's request-id middleware, or "" if absent.
Types ¶
type APIError ¶
type APIError struct {
Status int
Code string
Message string
Fields []FieldError
}
APIError is the framework's transport-level error. It carries an HTTP status, a stable code, a human message, and an optional field-keyed detail list. It implements error, so handlers may return it directly, and an ErrorMapper may produce it from any domain error.
type Accepted ¶
type Accepted[T any] struct{ Body T }
Accepted wraps a Resp body — the encoder emits 202 Accepted.
type Action ¶
type Action[Req, Resp any] struct { ID string // operationId, dotted snake — unique across the registry Method string // "GET", "POST", "PATCH", ... Path string // chi-style, e.g. "/persons/{id}" Summary string Description string Tags []string Statuses []StatusDoc // Deprecated marks the operation deprecated in the OpenAPI document. Deprecated bool // Security lists the security requirements for this operation, overriding any // registry-wide WithSecurity for this action. Each entry maps a scheme name // (declared via WithSecurityScheme) to its required scopes. A nil slice // inherits the registry-wide default; a non-nil slice overrides it, and an // explicitly empty slice ([]SecurityRequirement{}) marks the operation public // — it emits "security: []" so the operation opts out of any global // requirement. Security []SecurityRequirement // Timeout, when > 0, bounds the handler with a context deadline; a handler // that honors ctx and overruns yields a 504. Timeout time.Duration // Middleware wraps only this action's handler, innermost-first. Use it for // per-route concerns such as authentication on a single endpoint. Middleware []Middleware Handle func(ctx context.Context, req Req) (Resp, error) }
Action is one route declared once. Req and Resp are the typed request and response. A zero-field Req is allowed; Resp may be Empty, Created[T], Accepted[T], Response[T], or any struct.
type Created ¶
type Created[T any] struct{ Body T }
Created wraps a Resp body — the encoder emits 201 Created.
type ErrorMapper ¶
ErrorMapper maps any handler error to an APIError, decoupling the framework from a caller's domain error model. Install one with WithErrorMapper; when none is set, defaultErrorMapper is used.
type FieldError ¶
FieldError is one per-field validation failure.
type List ¶ added in v0.1.1
List is a conventional non-paginated collection body: a slice of items plus a metadata block carrying the total count. Like Page it is an ordinary 200 response body, offered so simple list endpoints across services share one wire shape — {"items": [...], "meta": {"total": N}}. Use Page instead when the collection is cursor-paginated. Construct it with NewList.
type ListMeta ¶ added in v0.1.1
type ListMeta struct {
// Total is the number of items in the result set.
Total int `json:"total"`
}
ListMeta carries count metadata for a List response body.
type Middleware ¶
Middleware is the standard net/http middleware shape: a function that wraps a handler and returns a new one. It is identical to chi's middleware signature, so chi and third-party middleware compose with go-actions directly.
type Observation ¶
type Observation struct {
ActionID string
Method string
Path string
// RequestID is the request correlation id (the same value carried by the
// error envelope and echoed on the X-Request-ID response header), so access
// logs and metrics emitted from an observer correlate with the request.
RequestID string
Status int
Duration time.Duration
Err error
}
Observation is the per-request record handed to an ObserveFunc once an action handler completes — including a recovered panic, which is reported as status 500 with a non-nil Err.
type ObserveFunc ¶
type ObserveFunc func(Observation)
ObserveFunc receives one Observation per handled action request. Install one with WithObserver; it is the seam for access logging, latency metrics, and tracing. It must not write to the response.
type Option ¶
type Option func(*Registry)
Option configures a Registry at construction time.
func WithErrorMapper ¶
func WithErrorMapper(m ErrorMapper) Option
WithErrorMapper installs a custom ErrorMapper, replacing the default generic mapping. A nil mapper is ignored.
func WithInfo ¶
WithInfo sets the OpenAPI info block (title, description, version). The title also names the browsable _actions index. Empty arguments leave the corresponding default in place.
func WithMaxBodyBytes ¶
WithMaxBodyBytes caps the request body size; a larger body is rejected with a 413. The default is 1 MiB. Pass 0 for no limit. Negative values are ignored.
func WithMethodNotAllowedHandler ¶
WithMethodNotAllowedHandler overrides the default JSON 405 response for a known path reached with an unsupported method. A nil handler is ignored.
func WithMiddleware ¶
func WithMiddleware(mw ...Middleware) Option
WithMiddleware appends registry-wide middleware applied to every route — the actions, the self-documentation endpoints, and the 404/405 responses. The first middleware is outermost. It composes with chi and any net/http middleware. Caller middleware runs outside the framework's request-id and panic-recovery layers.
func WithNotFoundHandler ¶
WithNotFoundHandler overrides the default JSON 404 response for unmatched routes. A nil handler is ignored.
func WithObserver ¶
func WithObserver(fn ObserveFunc) Option
WithObserver installs a per-request observability hook invoked after each action completes with its id, status, latency, and error (panics included). It is the seam for access logging, metrics, and tracing. A nil hook is ignored.
func WithOpenAPIVersion ¶
WithOpenAPIVersion selects the declared OpenAPI dialect: "3.1.0" (default) or "3.0.3". The generated schema fragments are a common subset valid under both; only the declared version string changes. An unsupported value panics at construction.
func WithRequestIDGenerator ¶
WithRequestIDGenerator overrides how a correlation id is minted when a request arrives without an X-Request-ID / X-Amzn-Request-Id header. The default emits a UUIDv4. A nil generator is ignored.
func WithSecurity ¶
func WithSecurity(reqs ...SecurityRequirement) Option
WithSecurity sets the registry-wide default security requirements applied to every operation that does not declare its own Action.Security.
func WithSecurityScheme ¶
func WithSecurityScheme(name string, scheme SecurityScheme) Option
WithSecurityScheme registers a named OpenAPI security scheme under components.securitySchemes. Reference it from WithSecurity or Action.Security.
func WithServers ¶
WithServers sets the OpenAPI servers[] block so generated clients know the base URLs the contract is served at.
func WithStripPrefix ¶
WithStripPrefix configures a namespace prefix to strip from each action's declared Path when building the router. Use it when the Registry is mounted under that same prefix (e.g. WithStripPrefix("/v1") for a Registry mounted at "/v1" whose actions are declared at "/v1/..."). By default no prefix is stripped and actions route at their declared Path.
type Page ¶
type Page[T any] struct { Items []T `json:"items"` NextCursor string `json:"next_cursor,omitempty"` HasMore bool `json:"has_more"` }
Page is a conventional cursor-paginated list body: a slice of items plus an opaque next cursor and a has-more flag. It is an ordinary 200 response body, offered so paginated endpoints across services share one wire shape.
type Registry ¶
type Registry struct {
// contains filtered or unexported fields
}
Registry stores registered actions and, after Freeze, the pre-built self-documentation artifacts.
func NewRegistry ¶
NewRegistry returns an empty Registry configured by the given options. With no options it uses a neutral OpenAPI info block, the default ErrorMapper, a 1 MiB request-body cap, panic recovery, request-id propagation, and JSON 404/405 responses, and mounts actions at their declared paths (no prefix stripping).
func (*Registry) Freeze ¶
func (r *Registry) Freeze()
Freeze seals the registry. It validates every action declaration and panics on a malformed action, a duplicate ID, or a duplicate Method+Path, then builds the OpenAPI document and the _actions index. After Freeze, Register panics.
func (*Registry) Handler ¶
Handler returns the http.Handler mounting every action plus the three self-documentation endpoints (/openapi.json, /openapi.yaml, /_actions). It panics if the registry is not frozen.
func (*Registry) OpenAPIJSON ¶
OpenAPIJSON returns the pre-built OpenAPI 3.1 JSON bytes. Valid after Freeze.
func (*Registry) OpenAPIYAML ¶
OpenAPIYAML returns the pre-built OpenAPI 3.1 YAML bytes. Valid after Freeze.
type Response ¶
Response wraps a body with an explicit status and optional response headers, for handlers that need control beyond Created/Accepted/Empty — e.g. setting Cache-Control or ETag, or returning a non-standard 2xx. Status defaults to 200 when zero. For OpenAPI schema generation it unwraps to its Body type.
type SecurityRequirement ¶
SecurityRequirement maps a security-scheme name to the scopes it requires. For apiKey and http schemes the scope list is empty, e.g. SecurityRequirement{"ApiKeyAuth": nil}.
type SecurityScheme ¶
type SecurityScheme struct {
Type string // "apiKey" | "http" | "oauth2" | "openIdConnect"
Description string
Name string // apiKey: the header/query/cookie parameter name
In string // apiKey: "header" | "query" | "cookie"
Scheme string // http: "bearer" | "basic"
BearerFormat string // http bearer: a hint such as "JWT"
}
SecurityScheme describes one OpenAPI security scheme, emitted under components.securitySchemes. Declare schemes with WithSecurityScheme and reference them by name from WithSecurity (registry-wide) or Action.Security (per operation). The BearerAuth and APIKeyAuth constructors cover the common cases.
func APIKeyAuth ¶
func APIKeyAuth(in, name string) SecurityScheme
APIKeyAuth returns an apiKey scheme carried in the given location ("header", "query", or "cookie") under the given parameter name.
func BearerAuth ¶
func BearerAuth(bearerFormat string) SecurityScheme
BearerAuth returns an HTTP bearer-token scheme. bearerFormat is an optional hint (e.g. "JWT") and may be "".
type Server ¶
Server is one entry of the OpenAPI servers[] block. Declare them with WithServers so generated clients know the base URLs.
type Validatable ¶
type Validatable interface {
Validate() error
}
Validatable is the optional escape hatch for validation a struct tag cannot express. A request type that implements it has Validate called after the tag-driven rules pass; a returned *APIError contributes its field details to the 422 response, and any other error becomes a single message-level failure. Implement it on the value or pointer receiver.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package actiontest provides test helpers for the action framework: Invoke runs an action's Handle directly, and NewServer freezes a registry and returns an httptest.Server exercising the full decode/validate/encode pipeline.
|
Package actiontest provides test helpers for the action framework: Invoke runs an action's Handle directly, and NewServer freezes a registry and returns an httptest.Server exercising the full decode/validate/encode pipeline. |
|
Command example runs the pet-store API built with go-actions and serves the three self-documenting endpoints alongside it: /openapi.json, /openapi.yaml, and the browsable /_actions index.
|
Command example runs the pet-store API built with go-actions and serves the three self-documenting endpoints alongside it: /openapi.json, /openapi.yaml, and the browsable /_actions index. |
|
openapi-snapshot
command
Command openapi-snapshot writes or checks a committed OpenAPI contract snapshot, demonstrating the contract-drift guard pattern.
|
Command openapi-snapshot writes or checks a committed OpenAPI contract snapshot, demonstrating the contract-drift guard pattern. |
|
petstore
Package petstore builds the example action registry shared by the runnable server example and the OpenAPI snapshot tool.
|
Package petstore builds the example action registry shared by the runnable server example and the OpenAPI snapshot tool. |
|
Package foundationx adapts the github.com/mrz1836/go-foundation error model to the go-actions ErrorMapper seam.
|
Package foundationx adapts the github.com/mrz1836/go-foundation error model to the go-actions ErrorMapper seam. |
