actions

package module
v0.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 25, 2026 License: MIT Imports: 23 Imported by: 0

README

🎬  go-actions

Typed HTTP actions for Go — one declaration, a handler and an OpenAPI 3.1 contract that can't drift


Release Go Version License


CI / CD    Build Last Commit      Quality    Go Report Coverage
Security    Scorecard Security      Docs    Go Reference Bitcoin


Project Navigation
📦 Installation ⚡ Quick Start 🧪 Examples & Tests
📚 Documentation 🛠️ Code Standards 📊 Benchmarks
🤖 AI Usage ⚖️ License 👥 Maintainers

🧩 About

go-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 each declaration — all from the same reflected types — 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 action index.

Because every artifact derives from the same types, the published contract cannot drift from runtime behavior. Freeze() enforces invariants at startup — unique IDs, unique method+path, and documented statuses — so a misconfigured route fails on boot, not in production.

  • One declaration, many artifacts — handler, schema, OpenAPI, and docs all generated from one typed struct.
  • Production-safe by default — panic recovery, a 1 MiB request-body cap, request-id propagation, and JSON 404/405 responses are on out of the box, every one overridable.
  • Composable middleware — registry-wide (WithMiddleware) and per-action (Action.Middleware) using the standard chi/net-http signature, for auth, CORS, logging, and rate limiting.
  • Observability hook — one WithObserver callback receives each request's action id, status, latency, and error — the seam for access logs, metrics, and tracing.
  • Documented auth — declare OpenAPI securitySchemes and per-operation security (with BearerAuth/APIKeyAuth helpers) so the contract states how to authenticate.
  • Pluggable error mapping — decouple your domain errors from the wire shape with an ErrorMapper.
  • Self-documenting — serve /openapi.json, /openapi.yaml, and a browsable /_actions index straight from the registry.
  • Struct-tag validation, with an escape hatchrequired, min, max, oneof, uuid, email, e164, rfc3339 (the same tags feed the JSON Schema), plus a Validatable interface for rules a tag can't express.
  • No domain coupling — the core imports only the standard library, go-chi/chi/v5, google/uuid, and gopkg.in/yaml.v3.

Why it matters: in 2026, your API contract is consumed by SDK generators, API gateways, and AI agents calling tools. A contract generated from the code that actually serves traffic is one you never have to hand-reconcile.


📦 Installation

go-actions requires a supported release of Go.

go get -u github.com/mrz1836/go-actions

Get the MAGE-X build tool for development:

go install github.com/mrz1836/mage-x/cmd/magex@latest

⚡ Quick Start

1. Declare an action

An Action[Req, Resp] declares one route. Request fields bind from the JSON body or from path/query/header tags; validate tags are enforced before your handler runs.

package main

import (
	"context"
	"net/http"

	"github.com/mrz1836/go-actions"
)

type createUserReq struct {
	Name  string `json:"name"  validate:"required,min=1,max=64"`
	Email string `json:"email" validate:"required,email"`
}

type user struct {
	ID    string `json:"id"`
	Name  string `json:"name"`
	Email string `json:"email"`
}

func createUser() actions.Action[createUserReq, actions.Created[user]] {
	return actions.Action[createUserReq, actions.Created[user]]{
		ID:      "users.create",
		Method:  http.MethodPost,
		Path:    "/users",
		Summary: "Create a user",
		Tags:    []string{"users"},
		Statuses: []actions.StatusDoc{
			{Code: http.StatusCreated, Description: "the created user"},
			{Code: http.StatusUnprocessableEntity, Description: "invalid body", Error: true},
		},
		Handle: func(_ context.Context, req createUserReq) (actions.Created[user], error) {
			u := user{ID: "u_1", Name: req.Name, Email: req.Email}
			return actions.Created[user]{Body: u}, nil
		},
	}
}

Response envelopes set the documented status: actions.Empty → 204, actions.Created[T] → 201, actions.Accepted[T] → 202. Returning any other value encodes as 200. For full control, return actions.Response[T] to set a custom status and response headers (e.g. Cache-Control/ETag), actions.Page[T] for a conventional cursor-paginated list body, or actions.List[T] for a non-paginated collection — {"items": [...], "meta": {"total": N}}. Build the latter with actions.NewList(items), which sets the total and normalizes a nil slice to []:

Handle: func(ctx context.Context, _ listReq) (actions.List[user], error) {
    return actions.NewList(store.all()), nil // 200 {"items":[...],"meta":{"total":N}}
}

Path, query, and header parameters bind by struct tag (path:, query:, header:). Scalars convert automatically — string, bool, the integer and float kinds, and time.Time (parsed as RFC3339 or a bare 2006-01-02 date; a malformed value yields a 422). Any of these may be a pointer, so an absent optional parameter stays nil rather than a zero value:

type listReq struct {
    Active *bool      `json:"-" query:"active"` // nil when ?active= is absent
    Since  *time.Time `json:"-" query:"since"`  // RFC3339; 422 if malformed
    Limit  int        `json:"-" query:"limit" validate:"max=100"`
}
2. Register, freeze, and mount
func main() {
	reg := actions.NewRegistry(actions.WithInfo(
		"Users API",
		"Manage users.",
		"1.0.0",
	))

	actions.Register(reg, createUser())
	reg.Freeze() // validates declarations and builds the contract artifacts

	http.Handle("/", reg.Handler())
	_ = http.ListenAndServe(":8080", nil)
}

Register is the only typed seam — after Freeze() the registry is sealed and further Register calls panic. Handler() returns an http.Handler mounting every action plus the self-documentation endpoints.

3. Serve the contract

Handler() mounts three self-documenting endpoints automatically:

Endpoint Returns
/openapi.json the OpenAPI 3.1 document as JSON
/openapi.yaml the same document as YAML
/_actions a browsable HTML index (Markdown via Accept)

The /_actions index ships in core and is always on — no build tag required. You can also reach the raw bytes directly with reg.OpenAPIJSON() and reg.OpenAPIYAML() (for example, to write a committed snapshot).


Pluggable error handling

Handlers return ordinary Go errors. An ErrorMapper translates them into the transport-level APIError, decoupling the framework from your domain error model:

type APIError struct {
	Status  int
	Code    string
	Message string
	Fields  []FieldError
}

type ErrorMapper func(error) APIError

Install one with WithErrorMapper:

reg := actions.NewRegistry(actions.WithErrorMapper(func(err error) actions.APIError {
	if errors.Is(err, ErrNotFound) {
		return actions.APIError{
			Status:  http.StatusNotFound,
			Code:    actions.CodeNotFound,
			Message: "resource not found",
		}
	}
	return actions.APIError{
		Status:  http.StatusInternalServerError,
		Code:    actions.CodeInternal,
		Message: "an internal error occurred",
	}
}))

The default mapper passes an *APIError through unchanged (so handlers may return one directly) and maps every other error to a redacted 500, ensuring internal detail never reaches the wire. The error envelope is always {"error": ..., "code": ..., "request_id": ...}.

foundationx adapter — the optional foundationx sub-package provides a ready-made ErrorMapper that wires the go-foundation error model (*ValidationError → 422, ErrNotFound → 404). It lives in its own package so consumers that do not use go-foundation never pull it into their module graph:

import "github.com/mrz1836/go-actions/foundationx"

reg := actions.NewRegistry(actions.WithErrorMapper(foundationx.NewErrorMapper()))
Registry options
Option Effect
WithInfo(title, desc, version) Sets the OpenAPI info block; the title also names the _actions index.
WithErrorMapper(mapper) Installs a custom error mapper (replaces the default generic one).
WithStripPrefix(prefix) Strips a namespace prefix from each action's Path when routing (e.g. when the registry is mounted under that prefix).
WithMiddleware(mw...) Registry-wide middleware applied to every route (actions, self-docs, 404/405).
WithMaxBodyBytes(n) Caps the request body (default 1 MiB; 0 disables). Over-limit ⇒ 413.
WithObserver(fn) Per-request hook with action id, status, latency, and error.
WithRequestIDGenerator(fn) Overrides how a correlation id is minted when none is inbound (default UUIDv4).
WithNotFoundHandler(h) / WithMethodNotAllowedHandler(h) Override the JSON 404 / 405 defaults.
WithSecurityScheme(name, scheme) Declares an OpenAPI security scheme (BearerAuth/APIKeyAuth helpers).
WithSecurity(reqs...) Sets registry-wide default security requirements.
WithServers(servers...) Sets the OpenAPI servers[] block.
WithOpenAPIVersion(v) Declares the dialect: "3.1.0" (default) or "3.0.3".
Production middleware & safety

Every registry ships a built-in middleware chain wrapping the typed pipeline — all on by default and overridable:

  • Panic recovery — a panicking handler becomes a logged, redacted 500 (and a non-nil Observation.Err); the connection is never torn down.
  • Request-body cap — bodies over WithMaxBodyBytes (default 1 MiB) are rejected with 413. Pass 0 to disable.
  • Request-id propagation — an inbound X-Request-ID / X-Amzn-Request-Id is reused, otherwise one is generated; it is placed in the context (actions.RequestIDFromContext), echoed on the response, and included in every error envelope.
  • JSON 404 / 405 — unmatched routes and wrong methods return the standard error envelope, not chi's plain text.

Per-action knobs live on the Action struct:

actions.Action[Req, Resp]{
    // ...
    Middleware: []actions.Middleware{authOnly}, // wraps just this route
    Timeout:    2 * time.Second,                // ctx deadline → 504 on overrun
    Security:   []actions.SecurityRequirement{{"BearerAuth": {"admin"}}},
    Deprecated: true,                           // marked deprecated in OpenAPI
}

Wire observability with one hook:

reg := actions.NewRegistry(actions.WithObserver(func(o actions.Observation) {
    slog.Info("request",
        "action", o.ActionID, "status", o.Status, "request_id", o.RequestID,
        "ms", o.Duration.Milliseconds(), "err", o.Err)
}))
Auth & OpenAPI security

Declare security schemes once; reference them registry-wide or per action. They surface in the generated contract under components.securitySchemes and security:

reg := actions.NewRegistry(
    actions.WithSecurityScheme("BearerAuth", actions.BearerAuth("JWT")),
    actions.WithSecurityScheme("ApiKeyAuth", actions.APIKeyAuth("header", "X-API-Key")),
    actions.WithSecurity(actions.SecurityRequirement{"ApiKeyAuth": nil}), // default for all ops
    actions.WithServers(actions.Server{URL: "https://api.example.com", Description: "production"}),
)

go-actions does not authenticate requests itself — wire your auth as WithMiddleware or a per-action Middleware; the security blocks document how clients authenticate so SDK generators and gateways configure it correctly.

Validation tags

The validate struct tag drives both request validation and the generated JSON Schema constraints. Supported rules:

required, min=N, max=N, oneof=a b c, uuid, email, e164, rfc3339.

For strings and slices, min/max bound the length; for numbers they bound the value. Format rules (uuid, email, etc.) are skipped on an empty value — use required to reject emptiness.

For rules a tag can't express, a request type may implement Validatable (Validate() error); it runs after the tag rules and its field details merge into the 422 response.


📚 Documentation


Repository Features

This repository includes 25+ built-in features covering CI/CD, security, code quality, developer experience, and community tooling.

View the full Repository Features list →

Library Deployment

This project uses goreleaser for streamlined binary and library deployment to GitHub. To get started, install it via:

brew install goreleaser

The release process is defined in the .goreleaser.yml configuration file.

Then create and push a new Git tag using:

magex version:bump push=true bump=patch branch=master

This process ensures consistent, repeatable releases with properly versioned artifacts and metadata.

Pre-commit Hooks

Set up the Go-Pre-commit System to run the same formatting, linting, and tests defined in AGENTS.md before every commit:

go install github.com/mrz1836/go-pre-commit/cmd/go-pre-commit@latest
go-pre-commit install

The system is configured via modular env files in .github/env/ and provides 17x faster execution than traditional Python-based pre-commit hooks. See the complete documentation for details.

GitHub Workflows

All workflows are driven by modular configuration in .github/env/ — no YAML editing required.

View all workflows and the control center →

Updating Dependencies

To update all dependencies (Go modules, linters, and related tools), run:

magex deps:update

This command ensures all dependencies are brought up to date in a single step, including Go modules and any tools managed by MAGE-X. It is the recommended way to keep your development environment and CI in sync with the latest versions.

Build Commands

View all build commands

magex help

🧪 Examples & Tests

All unit tests run via GitHub Actions and use Go version 1.25.x. View the configuration file.

The examples/ directory contains a runnable pet-store API:

  • examples/main.go — a server declaring actions, mounting Handler(), and serving /openapi.json, /openapi.yaml, and /_actions.
  • examples/openapi-snapshot — a contract-drift guard that writes or checks a committed OpenAPI snapshot (wire check into CI to fail the build when the generated contract drifts).
  • examples/petstore — the shared registry both examples use.

Run the example server:

cd examples && go run .
# then browse http://localhost:8080/_actions

The actiontest helper exercises actions through the real pipeline or directly:

import "github.com/mrz1836/go-actions/actiontest"

// Spin up a test server running the full decode/validate/encode pipeline:
srv := actiontest.NewServer(t, reg)

// Or invoke a handler directly, bypassing decode/validate/encode:
resp, err := actiontest.Invoke(t, createUser(), createUserReq{Name: "Ada", Email: "ada@example.com"})

Run all tests (fast):

magex test

Run all tests with race detector (slower):

magex test:race

📊 Benchmarks

Run the Go benchmarks:

magex bench

Benchmarks cover the hot path — request decoding, validation, and response encoding through the typed pipeline — plus the one-time OpenAPI contract generation.


🛠️ Code Standards

Read more about this Go project's code standards.


🤖 AI Usage & Assistant Guidelines

Read the AI Usage & Assistant Guidelines for details on how AI is used in this project and how to interact with the AI assistants.


👥 Maintainers

MrZ
MrZ

🤝 Contributing

View the contributing guidelines and please follow the code of conduct.

How can I help?

All kinds of contributions are welcome 🙌! The most basic way to show your support is to star 🌟 the project, or to raise issues 💬. You can also support this project by becoming a sponsor on GitHub 👏 or by making a bitcoin donation to ensure this journey continues indefinitely! 🚀

Stars


📝 License

License

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

View Source
const (
	CodeValidation         = "VALIDATION_ERROR"
	CodeBadRequest         = "BAD_REQUEST"
	CodeUnauthorized       = "UNAUTHORIZED"
	CodeForbidden          = "FORBIDDEN"
	CodeNotFound           = "NOT_FOUND"
	CodeConflict           = "CONFLICT"
	CodePayloadTooLarge    = "PAYLOAD_TOO_LARGE"
	CodeTooManyRequests    = "TOO_MANY_REQUESTS"
	CodeInternal           = "INTERNAL_ERROR"
	CodeMethodNotAllowed   = "METHOD_NOT_ALLOWED"
	CodeTimeout            = "TIMEOUT"
	CodeServiceUnavailable = "SERVICE_UNAVAILABLE"
)

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

func Register[Req, Resp any](reg *Registry, a Action[Req, Resp])

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

func RequestIDFromContext(ctx context.Context) string

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.

func (*APIError) Error

func (e *APIError) Error() string

Error implements the error interface.

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 Empty

type Empty struct{}

Empty is a Resp marker — the encoder emits 204 No Content.

type ErrorMapper

type ErrorMapper func(error) APIError

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

type FieldError struct {
	Field   string `json:"field"`
	Message string `json:"message"`
}

FieldError is one per-field validation failure.

type List added in v0.1.1

type List[T any] struct {
	Items []T      `json:"items"`
	Meta  ListMeta `json:"meta"`
}

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.

func NewList added in v0.1.1

func NewList[T any](items []T) List[T]

NewList wraps items in a List with Meta.Total set to len(items). A nil slice is normalized to an empty slice so the body encodes "items": [] rather than "items": null.

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

type Middleware = func(http.Handler) http.Handler

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

func WithInfo(title, description, version string) Option

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

func WithMaxBodyBytes(n int64) Option

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

func WithMethodNotAllowedHandler(h http.Handler) Option

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

func WithNotFoundHandler(h http.Handler) Option

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

func WithOpenAPIVersion(v string) Option

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

func WithRequestIDGenerator(gen func() string) Option

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

func WithServers(servers ...Server) Option

WithServers sets the OpenAPI servers[] block so generated clients know the base URLs the contract is served at.

func WithStripPrefix

func WithStripPrefix(prefix string) Option

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

func NewRegistry(opts ...Option) *Registry

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

func (r *Registry) Handler() http.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

func (r *Registry) OpenAPIJSON() []byte

OpenAPIJSON returns the pre-built OpenAPI 3.1 JSON bytes. Valid after Freeze.

func (*Registry) OpenAPIYAML

func (r *Registry) OpenAPIYAML() []byte

OpenAPIYAML returns the pre-built OpenAPI 3.1 YAML bytes. Valid after Freeze.

type Response

type Response[T any] struct {
	Status int
	Header http.Header
	Body   T
}

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

type SecurityRequirement map[string][]string

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

type Server struct {
	URL         string
	Description string
}

Server is one entry of the OpenAPI servers[] block. Declare them with WithServers so generated clients know the base URLs.

type StatusDoc

type StatusDoc struct {
	Code        int
	Description string
	Error       bool
}

StatusDoc documents one outcome of an action.

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.

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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL