Documentation
¶
Overview ¶
Package rest builds type-safe HTTP APIs with OpenAPI documentation generated from the same declarations that wire up the handlers — no separate codegen step, no struct tags to keep in sync.
A Controller groups Routes under a path prefix, tag, and guards. Each Route declares its OpenAPI doc (summary, parameters, request body, responses) and a Handler. ReflectParameter/ReflectResponse/ReflectRequestBody derive the OpenAPI schema straight from a Go type via oas.ReflectType, so entity structs don't need to be described twice.
Errors are mapped to HTTP status codes declaratively with ErrorOf (sentinel, matched via errors.Is) and ErrorAs (typed, matched via errors.As), at three layers — global (MapErrorOf/MapErrorAs), Controller.MapError, and Route.MapError — resolved most-specific first. A typed error's own json-tagged fields are merged into both the response body and the auto-generated OpenAPI schema for its status code.
rest itself is HTTP-engine-agnostic: Adapter is the interface an HTTP engine implements to serve a Server's controllers. The reference implementation is Fiber, in the adapter/fiber subpackage; other engines (Gin, Echo, net/http) can implement Adapter the same way.
Index ¶
- func JoinPath(prefix, path string) string
- func MapErrorAs[T error](status int, description ...string)
- func MapErrorOf(err error, status int, description ...string)
- func MustBodyJson[T any](ctx Context, key string) T
- func MustHeader[T any](ctx Context, name string, optional ...T) T
- func MustParam[T any](ctx Context, name string, optional ...T) T
- func MustQuery[T any](ctx Context, name string, optional ...T) T
- type Adapter
- type Context
- type Controller
- func (c *Controller) ApiBearerAuth() *Controller
- func (c *Controller) ApiTag(value string) *Controller
- func (c *Controller) GuardList() []*Guard
- func (c *Controller) MapError(mapping ErrorMapping) *Controller
- func (c *Controller) Path(value string) *Controller
- func (c *Controller) Route(method, path string, build func(*Route)) *Controller
- func (c *Controller) UseGuard(guards ...*Guard) *Controller
- type ErrorMapping
- type Guard
- type GuardBuilder
- type Parameter
- type RawContext
- type RequestBody
- type Response
- func (r *Response) ContentTypeJson() *Response
- func (r *Response) Description(value string) *Response
- func (r *Response) Error(err error) *Response
- func (r *Response) Example(value any) *Response
- func (r *Response) HTTPBody() any
- func (r *Response) HTTPStatus() int
- func (r *Response) JSON(value any) *Response
- func (r *Response) Schema(build func(*oas.Schema)) *Response
- func (r *Response) Status(code int) *Response
- type Route
- func (r *Route) ApiDescription(value string) *Route
- func (r *Route) ApiParameter(p *Parameter) *Route
- func (r *Route) ApiRequestBody(rb *RequestBody) *Route
- func (r *Route) ApiResponse(status int, arg any) *Route
- func (r *Route) ApiSummary(value string) *Route
- func (r *Route) GuardList() []*Guard
- func (r *Route) Handler(fn func(Context) *Response) *Route
- func (r *Route) MapError(mapping ErrorMapping) *Route
- func (r *Route) Serve(ctx Context) *Response
- func (r *Route) UseGuard(guards ...*Guard) *Route
- type Schema
- type Server
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func JoinPath ¶
JoinPath joins a controller's path prefix with a route's path, normalizing slashes. Adapters use this to register routes on the underlying engine — paths keep the engine's own param syntax (e.g. Fiber's ":id").
func MapErrorAs ¶
MapErrorAs registers a global typed error->status mapping (errors.As).
func MapErrorOf ¶
MapErrorOf registers a global sentinel error->status mapping (errors.Is). It's the default for every route that doesn't declare its own override via Controller.MapError/Route.MapError.
func MustBodyJson ¶
MustBodyJson decodes the request body as JSON into T. If key is non-empty, it's treated as a top-level field name and only that sub-value is decoded into T; an empty key decodes the whole body.
func MustHeader ¶
MustHeader extracts and converts a header to T, panicking if it's missing (unless an optional default value is given) or can't be converted.
Types ¶
type Adapter ¶
type Adapter interface {
// Bind wires every controller/route from server onto the underlying engine.
Bind(server *Server) error
// Listen starts serving on address.
Listen(address string) error
}
Adapter binds a Server's controllers/routes onto a concrete HTTP engine. Fiber ships as the reference implementation (github.com/leandroluk/gox/rest/adapter/fiber); Gin/Echo/Mux/etc can plug in later by implementing the same interface.
type Context ¶
type Context interface {
RawContext
// Response starts building the HTTP response for this request.
Response() *Response
}
Context is the adapter-agnostic request context passed to handlers and guards.
func NewContext ¶
func NewContext(route *Route, raw RawContext) Context
NewContext wraps a RawContext (produced by an adapter) into a rest.Context bound to route, so Response().Error(err) can resolve the layered error registry (route -> controller -> global).
type Controller ¶
type Controller struct {
PathPrefix string
Routes []*Route
// contains filtered or unexported fields
}
Controller groups routes under a common path prefix, tag, guards, and error-mapping defaults.
func NewController ¶
func NewController(build func(*Controller)) *Controller
NewController builds a Controller via the given configuration callback.
func (*Controller) ApiBearerAuth ¶
func (c *Controller) ApiBearerAuth() *Controller
ApiBearerAuth marks every route in this controller as requiring bearer auth.
func (*Controller) ApiTag ¶
func (c *Controller) ApiTag(value string) *Controller
ApiTag sets the OpenAPI tag for every route in this controller.
func (*Controller) GuardList ¶
func (c *Controller) GuardList() []*Guard
GuardList exposes this controller's guards, run before every route's own, for adapters.
func (*Controller) MapError ¶
func (c *Controller) MapError(mapping ErrorMapping) *Controller
MapError registers an error->status mapping shared by every route in this controller that doesn't declare its own override via Route.MapError.
func (*Controller) Path ¶
func (c *Controller) Path(value string) *Controller
Path sets the base path prefix for every route in this controller.
func (*Controller) Route ¶
func (c *Controller) Route(method, path string, build func(*Route)) *Controller
Route declares a new route under this controller.
func (*Controller) UseGuard ¶
func (c *Controller) UseGuard(guards ...*Guard) *Controller
UseGuard attaches guards run before every route in this controller.
type ErrorMapping ¶
type ErrorMapping struct {
// contains filtered or unexported fields
}
ErrorMapping is a declarative error->status mapping built via ErrorOf or ErrorAs. Register it globally with MapErrorOf/MapErrorAs, or scope it to a single Controller/Route via their MapError method (Go doesn't allow generic methods, so ErrorAs[T] has to stay a package-level function; MapError just stores the value it returns).
func ErrorAs ¶
func ErrorAs[T error](status int, description ...string) ErrorMapping
ErrorAs builds a typed error mapping, matched at resolution time via errors.As. T must be the concrete type carried by the error chain (typically a pointer, e.g. *ValidationError, mirroring what you'd pass to errors.As yourself).
type Guard ¶
type Guard struct {
// contains filtered or unexported fields
}
Guard runs before a route's handler; a non-nil Response short-circuits the request (e.g. 401 on missing auth) without reaching the handler.
func NewGuard ¶
func NewGuard(build func(*GuardBuilder)) *Guard
NewGuard builds a Guard via the given configuration callback.
type GuardBuilder ¶
type GuardBuilder struct {
// contains filtered or unexported fields
}
GuardBuilder configures a Guard.
func (*GuardBuilder) Handler ¶
func (b *GuardBuilder) Handler(fn func(Context) *Response) *GuardBuilder
Handler sets the function that runs for this guard.
type Parameter ¶
Parameter is a plain alias to oas.Parameter.
func ReflectParameter ¶
ReflectParameter builds a Parameter for T named name, with its schema derived from T's shape (via oas.ReflectType — same reflection already used for entity schemas). Chain .InPath()/.InQuery()/etc and .Description() on the result.
type RawContext ¶
type RawContext interface {
// Param returns a path parameter's raw value, and whether it was present.
Param(name string) (string, bool)
// Query returns a query parameter's raw value, and whether it was present.
Query(name string) (string, bool)
// Header returns a request header's raw value, and whether it was present.
Header(name string) (string, bool)
// Body returns the raw request body.
Body() []byte
// Ctx returns the request's context.Context, for cancellation/deadline
// propagation into downstream calls (DB queries, usecases, etc).
Ctx() context.Context
}
RawContext is implemented by adapters (one per HTTP engine — Fiber at minimum) to expose the underlying request. rest builds Context and error resolution on top of it, so handlers/guards never touch the engine directly.
type RequestBody ¶
type RequestBody = oas.RequestBody
RequestBody is a plain alias to oas.RequestBody.
func ReflectRequestBody ¶
func ReflectRequestBody[T any]() *RequestBody
ReflectRequestBody builds a RequestBody whose JSON schema is derived from T's shape.
type Response ¶
type Response struct {
// contains filtered or unexported fields
}
Response is a dual-purpose builder. At doc-declaration time (route.ApiResponse, ReflectResponse) it configures OpenAPI metadata (Description/ContentTypeJson/ Schema/Example). At request time (returned from a Handler) the same type carries the actual HTTP status/body to send — Status/JSON/Error.
func Recover ¶
Recover converts a recovered panic value into a Response via the same error-mapping path as Error(err): if recovered is an error, it's resolved against the registry as usual; otherwise it's wrapped so it still falls back to 500 with a {"message": ...} body instead of crashing the request.
Adapters call this from their own recover(); it's here (not per-adapter) so every engine gets identical panic->response behavior. This exists because MustParam/MustBodyJson/MustHeader/MustQuery panic by design, and callers commonly propagate domain errors via panic too (e.g. panic(ErrNotFound) from inside a usecase), relying on the HTTP layer to recover and map them.
func ReflectResponse ¶
ReflectResponse builds a doc Response whose schema is derived from T's shape.
func (*Response) ContentTypeJson ¶
ContentTypeJson marks this response's content type as application/json.
func (*Response) Description ¶
Description sets the OpenAPI description for this response.
func (*Response) Error ¶
Error resolves err against the route/controller/global error registry (most specific first) and sets status + {"message": ...} body accordingly, falling back to 500 if nothing matches. An explicit prior call to Status always wins over the resolved mapping.
func (*Response) HTTPStatus ¶
HTTPStatus returns the resolved HTTP status code, defaulting to 200.
type Route ¶
Route describes a single HTTP endpoint: its OpenAPI documentation, guards, error-mapping overrides, and the handler that actually serves it.
func (*Route) ApiDescription ¶
ApiDescription sets the OpenAPI description for this route.
func (*Route) ApiParameter ¶
ApiParameter documents a single request parameter (path/query/header/cookie).
func (*Route) ApiRequestBody ¶
func (r *Route) ApiRequestBody(rb *RequestBody) *Route
ApiRequestBody documents the request body.
func (*Route) ApiResponse ¶
ApiResponse declares (or overrides) the OpenAPI doc for a status code. arg accepts either a pre-built *Response (e.g. from ReflectResponse) or a builder callback func(*Response) — Go has no method overloading, so this mirrors ApiRequestBody/ApiParameter's "give me a built value" style while still allowing the inline-callback style used for one-off responses.
func (*Route) ApiSummary ¶
ApiSummary sets the OpenAPI summary for this route.
func (*Route) GuardList ¶
GuardList exposes this route's own guards (run after the controller's) for adapters.
func (*Route) MapError ¶
func (r *Route) MapError(mapping ErrorMapping) *Route
MapError registers an error->status mapping scoped to this route only, taking priority over the controller and global registries. Build the mapping with ErrorOf (sentinel, errors.Is) or ErrorAs[T] (typed, errors.As).
type Schema ¶
Schema is a plain alias to oas.Schema — rest doesn't need its own copy of the OpenAPI schema builder.
type Server ¶
type Server struct {
// contains filtered or unexported fields
}
Server holds the registered controllers and the adapter(s) that serve them.
func (*Server) ControllerList ¶
func (s *Server) ControllerList() []*Controller
ControllerList exposes registered controllers for adapters to walk.
func (*Server) Controllers ¶
func (s *Server) Controllers(controllers []*Controller) *Server
Controllers registers the given controllers with the server.
func (*Server) Document ¶
Document builds (lazily, once) the OpenAPI document describing every registered controller/route, auto-generating a response entry for every mapped error not already documented manually via ApiResponse.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
adapter
|
|
|
fiber
Package fiber is the reference rest.Adapter implementation, wiring rest.Server's controllers/routes onto a github.com/gofiber/fiber/v2 App.
|
Package fiber is the reference rest.Adapter implementation, wiring rest.Server's controllers/routes onto a github.com/gofiber/fiber/v2 App. |