Documentation
¶
Overview ¶
Package api holds REST helpers on top of web and orm: resource transformers, pagination envelopes, allowlisted query conventions (filter, sort, fields, include, pagination) and deprecation headers. See docs/api.md.
Index ¶
- Constants
- func Collection[T, R any](c *web.Ctx, items []T, fn func(T) R) error
- func Cursor[T, R any](c *web.Ctx, p orm.CursorPage[T], fn func(T) R) error
- func Deprecate(since, sunset time.Time, link string) func(http.Handler) http.Handler
- func Idempotency(store cache.Store, o IdempotencyOptions) func(http.Handler) http.Handler
- func Map[T, R any](items []T, fn func(T) R) []R
- func Page[T, R any](c *web.Ctx, p orm.Page[T], fn func(T) R) error
- func Register[In, Out any](g Registrar, pattern string, op Op, fn func(*web.Ctx, In) (Out, error)) *router.Route
- type Envelope
- type IdempotencyOptions
- type Links
- type Meta
- type Op
- type Operation
- type Option
- type Registrar
- type Request
Constants ¶
const IdempotencyHeader = "Idempotency-Key"
IdempotencyHeader is the request header carrying the key.
Variables ¶
This section is empty.
Functions ¶
func Collection ¶
Collection answers 200 with {"data": [...]}.
func Cursor ¶
Cursor answers 200 with a keyset page: meta.next_cursor and links.next (null on the last page).
func Deprecate ¶
Deprecate marks routes as deprecated (RFC 9745 Deprecation and RFC 8594 Sunset headers) and links to the replacement or migration guide. Apply it to a version group: g.Use(api.Deprecate(since, sunset, "/docs/v2")).
func Idempotency ¶ added in v0.15.0
Idempotency makes retried requests safe: the first request with an Idempotency-Key runs and its response (status below 500) is stored; repeats replay it with "Idempotent-Replayed: true". A repeat while the first is running gets 409, and reusing a key for a different request gets 422. If the store fails the request is refused with 503 (fail closed) rather than risking a duplicate side effect.
func Map ¶
func Map[T, R any](items []T, fn func(T) R) []R
Map transforms every item with fn; resources use it to turn models into their wire format: func Products(ps []models.Product) []ProductJSON { return api.Map(ps, Product) }.
func Page ¶
Page answers 200 with an offset page: data, meta (page, per_page, total, last_page) and links (self, next, prev).
func Register ¶ added in v0.15.0
func Register[In, Out any](g Registrar, pattern string, op Op, fn func(*web.Ctx, In) (Out, error)) *router.Route
Register adds a typed handler. The input is built from the query string, the JSON or form body and the path parameters (which win), and validated with In's `validate` tags (422 with field errors). The output is written as JSON. GET, HEAD and DELETE ignore the body. Pattern is "METHOD /path".
api.Register(g, "POST /products", api.Op{Name: "products.store"},
func(c *web.Ctx, in StoreProduct) (ProductJSON, error) { ... })
Types ¶
type Envelope ¶
type Envelope[R any] struct { Data []R `json:"data"` Meta *Meta `json:"meta,omitempty"` Links *Links `json:"links,omitempty"` }
Envelope is the JSON body of collections and pages.
type IdempotencyOptions ¶ added in v0.15.0
type IdempotencyOptions struct {
// Methods guarded (default POST and PATCH).
Methods []string
// Required answers 400 when the header is missing.
Required bool
// TTL keeps completed responses (default 24h).
TTL time.Duration
// LockTTL bounds an in-flight request (default 1 minute).
LockTTL time.Duration
// MaxBody bounds the request body that is fingerprinted (default 1 MiB).
MaxBody int64
// Scope separates callers so one cannot replay another's response.
// Default: the Authorization header; set it for cookie sessions (e.g.
// the user ID).
Scope func(r *http.Request) string
}
IdempotencyOptions tune Idempotency.
type Links ¶
type Links struct {
Self string `json:"self"`
Next *string `json:"next"`
Prev *string `json:"prev"`
}
Links point to neighbour pages; nil encodes as null.
type Meta ¶
type Meta struct {
Page int `json:"page,omitempty"`
PerPage int `json:"per_page"`
Total *int64 `json:"total,omitempty"`
LastPage int `json:"last_page,omitempty"`
NextCursor string `json:"next_cursor,omitempty"`
}
Meta describes a page.
type Op ¶ added in v0.15.0
type Op struct {
// Name is the route name (and the OpenAPI operationId).
Name string
Summary string
Description string
Tags []string
// Status is the success status; default 201 for POST, 204 when the
// output type is struct{}, 200 otherwise.
Status int
Deprecated bool
// Security lists the security schemes required (e.g. "bearer").
Security []string
}
Op describes a typed operation for the router and the OpenAPI document.
type Operation ¶ added in v0.15.0
type Operation struct {
Op
Method string
Path string
Params []string
In reflect.Type
Out reflect.Type
}
Operation is attached to every typed route (router.RouteInfo.Doc) so generators know its input and output types.
type Option ¶
type Option func(*spec)
Option allowlists one query convention for an endpoint.
type Registrar ¶ added in v0.15.0
type Registrar interface {
Match(methods []string, path string, h web.HandlerFunc) []*router.Route
}
Registrar is a router.Router or router.Group.
type Request ¶
type Request[T any] struct { Query orm.Query[T] Page int PerPage int Cursor string Includes []string }
Request is a query refined by the allowlisted conventions.