rocco

package module
v0.1.16 Latest Latest
Warning

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

Go to latest
Published: Mar 20, 2026 License: MIT Imports: 16 Imported by: 0

README

rocco

CI Status codecov Go Report Card CodeQL Go Reference License Go Version Release

Type-safe HTTP framework for Go with automatic OpenAPI generation.

Define your request and response types, wire up handlers, and get a fully-documented API with validation baked in.

Types Become Endpoints

type CreateUserInput struct {
    Name  string `json:"name" validate:"required,min=2"`
    Email string `json:"email" validate:"required,email"`
}

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

handler := rocco.NewHandler[CreateUserInput, UserOutput](
    "create-user", "POST", "/users",
    func(req *rocco.Request[CreateUserInput]) (UserOutput, error) {
        return UserOutput{
            ID:    "usr_123",
            Name:  req.Body.Name,
            Email: req.Body.Email,
        }, nil
    },
).WithErrors(rocco.ErrBadRequest, rocco.ErrConflict)

Your types define the contract. Rocco handles validation, serialization, error responses, and OpenAPI schema generation — all derived from the same source of truth.

Install

go get github.com/zoobz-io/rocco

Requires Go 1.24+.

Quick Start

package main

import (
    "fmt"

    "github.com/zoobz-io/openapi"
    "github.com/zoobz-io/rocco"
)

type CreateUserInput struct {
    Name  string `json:"name" validate:"required,min=2"`
    Email string `json:"email" validate:"required,email"`
}

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

func main() {
    engine := rocco.NewEngine()

    // Configure OpenAPI metadata
    engine.WithOpenAPIInfo(openapi.Info{
        Title:   "User API",
        Version: "1.0.0",
    })

    handler := rocco.NewHandler[CreateUserInput, UserOutput](
        "create-user", "POST", "/users",
        func(req *rocco.Request[CreateUserInput]) (UserOutput, error) {
            return UserOutput{
                ID:    "usr_123",
                Name:  req.Body.Name,
                Email: req.Body.Email,
            }, nil
        },
    ).
        WithSummary("Create a new user").
        WithTags("users").
        WithSuccessStatus(201).
        WithErrors(rocco.ErrBadRequest, rocco.ErrUnprocessableEntity)

    engine.WithHandlers(handler)

    // OpenAPI spec at /openapi, interactive docs at /docs
    fmt.Println("Server listening on :8080")
    engine.Start(rocco.HostAll, 8080)
}

Capabilities

Feature Description Docs
Type-Safe Handlers Generic handlers with compile-time type checking Handlers
Server-Sent Events Built-in SSE support for real-time streaming Streaming
Automatic OpenAPI Generate OpenAPI 3.1.0 specs from your types OpenAPI
Request Validation Struct tag validation with detailed error responses Concepts
Sentinel Errors Typed HTTP errors with OpenAPI schema generation Errors
Lifecycle Events Observable signals for logging, metrics, tracing Events

Why rocco?

  • Type-safe — Generic handlers catch errors at compile time, not runtime
  • Self-documenting — OpenAPI specs generated from the same types that validate requests
  • Explicit — No magic, no hidden behaviors, no struct tag DSLs for routing
  • Chi-powered — Built on the battle-tested Chi router with full middleware compatibility
  • Observable — Lifecycle events via capitan for metrics and tracing
  • Streaming-native — First-class SSE support with typed event streams

Contract-First by Default

Rocco enables a pattern: define types once, derive everything else.

Your request and response structs become the single source of truth. From them, rocco derives validation rules, OpenAPI schemas, error contracts, and documentation.

Define a type:

type CreateOrderInput struct {
    CustomerID string  `json:"customer_id" validate:"required,uuid4" description:"Customer UUID"`
    Items      []Item  `json:"items" validate:"required,min=1" description:"Order line items"`
    Total      float64 `json:"total" validate:"required,gt=0" description:"Order total in USD"`
}

Get an OpenAPI schema:

CreateOrderInput:
  type: object
  required: [customer_id, items, total]
  properties:
    customer_id:
      type: string
      format: uuid
      description: Customer UUID
    items:
      type: array
      minItems: 1
      description: Order line items
      items:
        $ref: '#/components/schemas/Item'
    total:
      type: number
      exclusiveMinimum: 0
      description: Order total in USD

Get consistent validation errors:

{
  "code": "VALIDATION_FAILED",
  "message": "validation failed",
  "details": {
    "fields": [
      {"field": "customer_id", "message": "must be a valid UUID"},
      {"field": "total", "message": "must be greater than 0"}
    ]
  }
}

No separate schema files. No manual sync between code and docs. The types ARE the contract.

Documentation

  • Overview — Design philosophy and architecture
Learn
Guides
Cookbook
Reference
  • API — Complete function documentation
  • Errors — All sentinel errors and detail types
  • Events — Lifecycle signals and field keys

Contributing

See CONTRIBUTING.md for guidelines.

License

MIT License — see LICENSE for details.

Documentation

Overview

Package rocco provides a type-safe HTTP framework for Go with automatic OpenAPI generation.

Rocco enables building HTTP APIs with compile-time type safety, automatic request validation, and OpenAPI 3.1.0 specification generation from your Go types.

Core Types

The framework is built around these primary types:

  • Engine: HTTP server managing routing, middleware, and handler registration
  • Handler: Type-safe request handler with generic input/output types
  • StreamHandler: Handler for Server-Sent Events (SSE) streaming
  • Request: Typed request container with body, parameters, and identity
  • Error: Structured API error with typed details for OpenAPI generation

Creating an Engine

Create an engine:

engine := rocco.NewEngine()

For authenticated APIs, configure an identity extractor:

engine := rocco.NewEngine().WithAuthenticator(func(ctx context.Context, r *http.Request) (rocco.Identity, error) {
    // Extract identity from request (e.g., JWT token)
    return identity, nil
})

Defining Handlers

Handlers are generic over input and output types:

handler := rocco.NewHandler[CreateUserInput, UserOutput](
    "create-user",
    "POST",
    "/users",
    func(req *rocco.Request[CreateUserInput]) (UserOutput, error) {
        return UserOutput{ID: "123", Name: req.Body.Name}, nil
    },
)

For handlers without a request body, use NoBody:

handler := rocco.NewHandler[rocco.NoBody, UserOutput](
    "get-user",
    "GET",
    "/users/{id}",
    func(req *rocco.Request[rocco.NoBody]) (UserOutput, error) {
        userID := req.Params.Path["id"]
        return UserOutput{ID: userID}, nil
    },
).WithPathParams("id")

Streaming (SSE)

For real-time server-to-client communication:

handler := rocco.NewStreamHandler[rocco.NoBody, PriceUpdate](
    "price-stream",
    "GET",
    "/prices/stream",
    func(req *rocco.Request[rocco.NoBody], stream rocco.Stream[PriceUpdate]) error {
        for {
            select {
            case <-stream.Done():
                return nil
            default:
                stream.Send(PriceUpdate{Price: 100.0})
            }
        }
    },
)

Error Handling

Use sentinel errors for typed HTTP error responses:

if user == nil {
    return UserOutput{}, rocco.ErrNotFound.WithMessage("user not found")
}

Declare errors in handler configuration:

handler.WithErrors(rocco.ErrNotFound, rocco.ErrBadRequest)

OpenAPI Generation

Register an OpenAPI endpoint to serve the generated specification:

engine.RegisterOpenAPIHandler("/openapi.json", rocco.Info{
    Title:   "My API",
    Version: "1.0.0",
})

Observability

Rocco emits lifecycle events via capitan for observability integration:

capitan.Hook(rocco.RequestReceived, func(ctx context.Context, e *capitan.Event) {
    method, _ := rocco.MethodKey.From(e)
    path, _ := rocco.PathKey.From(e)
    log.Printf("Request: %s %s", method, path)
})

Package rocco provides a type-safe HTTP framework for Go with automatic OpenAPI generation.

Index

Constants

View Source
const (
	HostAll      = ""          // Bind to all interfaces (0.0.0.0)
	HostLocal    = "localhost" // Bind to loopback (localhost)
	HostLoopback = "127.0.0.1" // Bind to loopback (127.0.0.1)
)

Common host constants for use with Engine.Start().

View Source
const ContentTypeJSON = "application/json"

ContentTypeJSON is the MIME type for JSON content.

View Source
const DefaultRedirectStatus = http.StatusFound

DefaultRedirectStatus is used when Redirect.Status is 0.

Variables

View Source
var (
	// ErrBadRequest indicates the request was invalid (400)
	ErrBadRequest = NewError[BadRequestDetails]("BAD_REQUEST", 400, "bad request")

	// ErrUnauthorized indicates missing or invalid authentication (401)
	ErrUnauthorized = NewError[UnauthorizedDetails]("UNAUTHORIZED", 401, "unauthorized")

	// ErrForbidden indicates the request is not allowed (403)
	ErrForbidden = NewError[ForbiddenDetails]("FORBIDDEN", 403, "forbidden")

	// ErrNotFound indicates the resource was not found (404)
	ErrNotFound = NewError[NotFoundDetails]("NOT_FOUND", 404, "not found")

	// ErrConflict indicates a conflict with existing data (409)
	ErrConflict = NewError[ConflictDetails]("CONFLICT", 409, "conflict")

	// ErrPayloadTooLarge indicates the request body exceeds the size limit (413)
	ErrPayloadTooLarge = NewError[PayloadTooLargeDetails]("PAYLOAD_TOO_LARGE", 413, "payload too large")

	// ErrUnprocessableEntity indicates the request was well-formed but semantically invalid (422)
	ErrUnprocessableEntity = NewError[UnprocessableEntityDetails]("UNPROCESSABLE_ENTITY", 422, "unprocessable entity")

	// ErrValidationFailed indicates request validation failed with detailed field errors (422)
	ErrValidationFailed = NewError[ValidationDetails]("VALIDATION_FAILED", 422, "validation failed")

	// ErrTooManyRequests indicates rate limiting (429)
	ErrTooManyRequests = NewError[TooManyRequestsDetails]("TOO_MANY_REQUESTS", 429, "too many requests")
)

Client errors (4xx)

View Source
var (
	// ErrInternalServer indicates an unexpected server error (500)
	ErrInternalServer = NewError[InternalServerDetails]("INTERNAL_SERVER_ERROR", 500, "internal server error")

	// ErrNotImplemented indicates the functionality is not implemented (501)
	ErrNotImplemented = NewError[NotImplementedDetails]("NOT_IMPLEMENTED", 501, "not implemented")

	// ErrBadGateway indicates an upstream provider returned an error (502)
	ErrBadGateway = NewError[BadGatewayDetails]("BAD_GATEWAY", 502, "bad gateway")

	// ErrServiceUnavailable indicates the service is temporarily unavailable (503)
	ErrServiceUnavailable = NewError[ServiceUnavailableDetails]("SERVICE_UNAVAILABLE", 503, "service unavailable")
)

Server errors (5xx)

View Source
var (
	// EngineCreated is emitted when an Engine instance is created.
	// Fields: none.
	EngineCreated = capitan.NewSignal("http.engine.created", "HTTP engine instance created")

	// EngineStarting is emitted when the server starts listening for requests.
	// Fields: AddressKey.
	EngineStarting = capitan.NewSignal("http.engine.starting", "HTTP server starting to listen for requests on configured address")

	// EngineShutdownStarted is emitted when graceful shutdown is initiated.
	// Fields: none.
	EngineShutdownStarted = capitan.NewSignal("http.engine.shutdown.started", "HTTP engine graceful shutdown initiated")

	// EngineShutdownComplete is emitted when shutdown finishes.
	// Fields: GracefulKey, ErrorKey (if failed).
	EngineShutdownComplete = capitan.NewSignal("http.engine.shutdown.complete", "HTTP engine shutdown completed, graceful or with error")
)

Engine lifecycle signals.

View Source
var (
	// RequestReceived is emitted when a request is received.
	// Fields: MethodKey, PathKey, HandlerNameKey.
	RequestReceived = capitan.NewSignal("http.request.received", "HTTP request received by engine and routed to handler")

	// RequestCompleted is emitted when a request completes successfully.
	// Fields: MethodKey, PathKey, HandlerNameKey, StatusCodeKey, DurationMsKey.
	RequestCompleted = capitan.NewSignal("http.request.completed", "HTTP request completed successfully with response sent")

	// RequestFailed is emitted when a request fails with an error.
	// Fields: MethodKey, PathKey, HandlerNameKey, StatusCodeKey, DurationMsKey, ErrorKey.
	RequestFailed = capitan.NewSignal("http.request.failed", "HTTP request failed during processing with error")
)

Request lifecycle signals.

View Source
var (
	// HandlerExecuting is emitted when handler execution begins.
	// Fields: HandlerNameKey.
	HandlerExecuting = capitan.NewSignal("http.handler.executing", "Handler execution started for incoming request")

	// HandlerSuccess is emitted when a handler returns successfully.
	// Fields: HandlerNameKey, StatusCodeKey.
	HandlerSuccess = capitan.NewSignal("http.handler.success", "Handler completed successfully and returned response")

	// HandlerError is emitted when a handler returns an error.
	// Fields: HandlerNameKey, ErrorKey.
	HandlerError = capitan.NewSignal("http.handler.error", "Handler returned unexpected error during execution")

	// HandlerSentinelError is emitted when a declared sentinel error is returned.
	// Fields: HandlerNameKey, ErrorKey, StatusCodeKey.
	HandlerSentinelError = capitan.NewSignal("http.handler.sentinel.error", "Handler returned declared sentinel error mapped to HTTP status")

	// HandlerUndeclaredSentinel is emitted when an undeclared sentinel error is returned (programming error).
	// Fields: HandlerNameKey, ErrorKey, StatusCodeKey.
	HandlerUndeclaredSentinel = capitan.NewSignal("http.handler.sentinel.undeclared", "Handler returned undeclared sentinel error, programming error detected")

	// RequestParamsInvalid is emitted when path or query parameter extraction fails.
	// Fields: HandlerNameKey, ErrorKey.
	RequestParamsInvalid = capitan.NewSignal("http.request.params.invalid", "Request path or query parameter extraction failed")

	// RequestBodyReadError is emitted when reading the request body fails.
	// Fields: HandlerNameKey, ErrorKey.
	RequestBodyReadError = capitan.NewSignal("http.request.body.read.error", "Failed to read request body from HTTP stream")

	// RequestBodyParseError is emitted when parsing the JSON request body fails.
	// Fields: HandlerNameKey, ErrorKey.
	RequestBodyParseError = capitan.NewSignal("http.request.body.parse.error", "Failed to parse JSON request body")

	// RequestValidationInputFailed is emitted when input validation fails.
	// Fields: HandlerNameKey, ErrorKey.
	RequestValidationInputFailed = capitan.NewSignal("http.request.validation.input.failed", "Request input validation failed against defined rules")

	// RequestValidationOutputFailed is emitted when output validation fails.
	// Fields: HandlerNameKey, ErrorKey.
	RequestValidationOutputFailed = capitan.NewSignal("http.request.validation.output.failed", "Response output validation failed, internal error")

	// RequestResponseMarshalError is emitted when marshaling the response fails.
	// Fields: HandlerNameKey, ErrorKey.
	RequestResponseMarshalError = capitan.NewSignal("http.request.response.marshal.error", "Failed to marshal response to JSON")

	// RequestBodyCloseError is emitted when closing the request body fails.
	// Fields: HandlerNameKey, ErrorKey.
	RequestBodyCloseError = capitan.NewSignal("http.request.body.close.error", "Failed to close request body stream")

	// ResponseBodyCloseError is emitted when closing an HTTP client response body fails.
	// Fields: EndpointKey, ErrorKey.
	ResponseBodyCloseError = capitan.NewSignal("http.response.body.close.error", "Failed to close HTTP client response body")

	// ResponseWriteError is emitted when writing the response body fails.
	// Fields: HandlerNameKey, ErrorKey.
	ResponseWriteError = capitan.NewSignal("http.response.write.error", "Failed to write response body to client")
)

Handler processing signals.

View Source
var (
	// AuthenticationFailed is emitted when authentication extraction fails.
	// Fields: MethodKey, PathKey, HandlerNameKey, ErrorKey.
	AuthenticationFailed = capitan.NewSignal("http.auth.failed", "Authentication extraction failed for request")

	// AuthenticationSucceeded is emitted when authentication succeeds.
	// Fields: MethodKey, PathKey, HandlerNameKey, IdentityIDKey, TenantIDKey.
	AuthenticationSucceeded = capitan.NewSignal("http.auth.succeeded", "Authentication succeeded for request")
)

Authentication signals.

View Source
var (
	// AuthorizationScopeDenied is emitted when scope requirement is not met.
	// Fields: MethodKey, PathKey, HandlerNameKey, IdentityIDKey, RequiredScopesKey, UserScopesKey.
	AuthorizationScopeDenied = capitan.NewSignal("http.authz.scope.denied", "Authorization failed due to insufficient scopes")

	// AuthorizationRoleDenied is emitted when role requirement is not met.
	// Fields: MethodKey, PathKey, HandlerNameKey, IdentityIDKey, RequiredRolesKey, UserRolesKey.
	AuthorizationRoleDenied = capitan.NewSignal("http.authz.role.denied", "Authorization failed due to insufficient roles")

	// AuthorizationSucceeded is emitted when authorization checks pass.
	// Fields: MethodKey, PathKey, HandlerNameKey, IdentityIDKey.
	AuthorizationSucceeded = capitan.NewSignal("http.authz.succeeded", "Authorization checks passed for request")
)

Authorization signals.

View Source
var (
	// StreamExecuting is emitted when stream handler execution begins.
	// Fields: HandlerNameKey.
	StreamExecuting = capitan.NewSignal("http.stream.executing", "Stream handler execution started for incoming request")

	// StreamStarted is emitted when SSE stream is established and headers sent.
	// Fields: HandlerNameKey.
	StreamStarted = capitan.NewSignal("http.stream.started", "SSE stream established and response headers sent")

	// StreamEnded is emitted when stream handler completes normally.
	// Fields: HandlerNameKey.
	StreamEnded = capitan.NewSignal("http.stream.ended", "SSE stream handler completed normally")

	// StreamClientDisconnected is emitted when client disconnects from stream.
	// Fields: HandlerNameKey.
	StreamClientDisconnected = capitan.NewSignal("http.stream.client.disconnected", "Client disconnected from SSE stream")

	// StreamError is emitted when stream handler encounters an error.
	// Fields: HandlerNameKey, ErrorKey.
	StreamError = capitan.NewSignal("http.stream.error", "SSE stream handler encountered error")
)

Stream (SSE) lifecycle signals.

View Source
var (
	// Engine fields.
	AddressKey = capitan.NewStringKey("address")

	// Request/Response fields.
	MethodKey      = capitan.NewStringKey("method")
	PathKey        = capitan.NewStringKey("path")
	HandlerNameKey = capitan.NewStringKey("handler_name")
	StatusCodeKey  = capitan.NewIntKey("status_code")
	DurationMsKey  = capitan.NewInt64Key("duration_ms")
	ErrorKey       = capitan.NewStringKey("error")
	GracefulKey    = capitan.NewBoolKey("graceful")
	EndpointKey    = capitan.NewStringKey("endpoint")

	// Authentication/Authorization fields.
	IdentityIDKey     = capitan.NewStringKey("identity_id")
	TenantIDKey       = capitan.NewStringKey("tenant_id")
	RequiredScopesKey = capitan.NewStringKey("required_scopes")
	UserScopesKey     = capitan.NewStringKey("user_scopes")
	RequiredRolesKey  = capitan.NewStringKey("required_roles")
	UserRolesKey      = capitan.NewStringKey("user_roles")

	// Rate limiting fields.
	LimitKeyKey     = capitan.NewStringKey("limit_key")
	CurrentValueKey = capitan.NewIntKey("current_value")
	ThresholdKey    = capitan.NewIntKey("threshold")
)

Event field keys (primitive types only).

View Source
var (
	// HandlerRegistered is emitted when a handler is registered with the engine.
	// Fields: HandlerNameKey, MethodKey, PathKey.
	HandlerRegistered = capitan.NewSignal("http.handler.registered", "HTTP handler registered with engine for specific route")
)

Handler registration signals.

View Source
var (
	// RateLimitExceeded is emitted when usage limit threshold is exceeded.
	// Fields: MethodKey, PathKey, HandlerNameKey, IdentityIDKey, LimitKeyKey, CurrentValueKey, ThresholdKey.
	RateLimitExceeded = capitan.NewSignal("http.ratelimit.exceeded", "Usage limit threshold exceeded for request")
)

Rate limiting signals.

Functions

func NewValidationError

func NewValidationError(fields []ValidationFieldError) error

NewValidationError creates a validation error with field details. Use this when implementing custom validators to return structured validation errors.

Types

type BadGatewayDetails

type BadGatewayDetails struct {
	Provider string `json:"provider,omitempty" description:"The upstream provider that failed"`
	Reason   string `json:"reason,omitempty" description:"Error details from the provider"`
}

BadGatewayDetails provides context for upstream provider errors.

type BadRequestDetails

type BadRequestDetails struct {
	Reason string `json:"reason,omitempty" description:"Why the request was invalid"`
}

BadRequestDetails provides context for bad request errors.

type Codec

type Codec interface {
	// ContentType returns the MIME type for this codec (e.g., "application/json").
	ContentType() string
	// Marshal encodes a value to bytes.
	Marshal(v any) ([]byte, error)
	// Unmarshal decodes bytes into a value.
	Unmarshal(data []byte, v any) error
}

Codec defines the interface for request/response serialization. Implementations handle marshaling and unmarshaling of handler payloads.

type ConflictDetails

type ConflictDetails struct {
	Reason string `json:"reason,omitempty" description:"What caused the conflict"`
}

ConflictDetails provides context for conflict errors.

type Endpoint

type Endpoint interface {
	// Process handles the HTTP request and writes the response.
	// Returns the HTTP status code written and any error encountered.
	Process(ctx context.Context, r *http.Request, w http.ResponseWriter) (int, error)

	// Spec returns the declarative specification for this handler
	Spec() HandlerSpec

	// ErrorDefs returns the declared error definitions for this handler.
	// Used by OpenAPI generation to extract error schemas.
	ErrorDefs() []ErrorDefinition

	// Middleware returns handler-specific middleware
	Middleware() []func(http.Handler) http.Handler

	// Lifecycle
	Close() error
}

Endpoint represents an HTTP route handler with metadata.

type Engine

type Engine struct {
	// contains filtered or unexported fields
}

Engine is the core HTTP server that manages routing, middleware, and handler registration.

func NewEngine

func NewEngine() *Engine

NewEngine creates a new Engine. Use WithAuthenticator to configure identity extraction for authenticated handlers.

func (*Engine) GenerateOpenAPI

func (e *Engine) GenerateOpenAPI(identity Identity) *openapi.OpenAPI

GenerateOpenAPI creates an OpenAPI specification from registered handlers. If identity is provided, only handlers accessible to that identity will be included.

func (*Engine) Router

func (e *Engine) Router() *http.ServeMux

Router returns the underlying http.ServeMux for advanced use cases. This allows power users to register custom routes that won't appear in OpenAPI documentation.

func (*Engine) Shutdown

func (e *Engine) Shutdown(ctx context.Context) error

Shutdown performs a graceful shutdown of the engine.

func (*Engine) Start

func (e *Engine) Start(host string, port int) error

Start begins listening for HTTP requests on the given host and port. Use an empty string for host to bind to all interfaces. This method blocks until the server is shutdown.

func (*Engine) WithAuthenticator

func (e *Engine) WithAuthenticator(extractor func(context.Context, *http.Request) (Identity, error)) *Engine

WithAuthenticator sets the identity extraction function for authenticated handlers. The extractor is called for handlers that require authentication (via WithAuthentication).

func (*Engine) WithCodec

func (e *Engine) WithCodec(codec Codec) *Engine

WithCodec sets the default codec for all handlers registered with this engine. Handlers that explicitly call WithCodec() will use their own codec instead.

func (*Engine) WithHandlers

func (e *Engine) WithHandlers(handlers ...Endpoint) *Engine

WithHandlers adds one or more Endpoints to the engine and returns the engine for chaining.

Threading model: All handler registration must complete before calling Start(). Calling WithHandlers concurrently or after Start() results in undefined behavior. This follows the standard Go pattern for HTTP server configuration.

func (*Engine) WithMiddleware

func (e *Engine) WithMiddleware(middleware ...func(http.Handler) http.Handler) *Engine

WithMiddleware adds global middleware to the engine and returns the engine for chaining.

func (*Engine) WithOpenAPIInfo

func (e *Engine) WithOpenAPIInfo(info openapi.Info) *Engine

WithOpenAPIInfo sets the OpenAPI Info metadata.

func (*Engine) WithSpec

func (e *Engine) WithSpec(spec *EngineSpec) *Engine

WithSpec sets the engine specification for OpenAPI generation.

func (*Engine) WithTag

func (e *Engine) WithTag(name, description string) *Engine

WithTag adds a tag with description to the OpenAPI specification. Tags are used to group operations in the documentation.

func (*Engine) WithTagGroup

func (e *Engine) WithTagGroup(name string, tags ...string) *Engine

WithTagGroup adds a tag group for hierarchical tag organization. Tag groups are rendered via the x-tagGroups vendor extension.

type EngineConfig

type EngineConfig struct {
	ReadTimeout  time.Duration // Maximum duration for reading entire request
	WriteTimeout time.Duration // Maximum duration for writing response
	IdleTimeout  time.Duration // Maximum time to wait for next request on keep-alive
}

EngineConfig holds configuration for the Engine.

func DefaultConfig

func DefaultConfig() *EngineConfig

DefaultConfig returns an EngineConfig with sensible defaults.

type EngineSpec

type EngineSpec struct {
	// OpenAPI Info
	Info openapi.Info `json:"info" yaml:"info"`

	// Global Tags with descriptions
	Tags []openapi.Tag `json:"tags,omitempty" yaml:"tags,omitempty"`

	// Tag Groups for hierarchical tag organization (x-tagGroups vendor extension)
	TagGroups []openapi.TagGroup `json:"x-tagGroups,omitempty" yaml:"x-tagGroups,omitempty"`

	// Servers
	Servers []openapi.Server `json:"servers,omitempty" yaml:"servers,omitempty"`

	// External Documentation
	ExternalDocs *openapi.ExternalDocumentation `json:"externalDocs,omitempty" yaml:"externalDocs,omitempty"`

	// Global Security (optional, for APIs that require auth on all endpoints)
	Security []openapi.SecurityRequirement `json:"security,omitempty" yaml:"security,omitempty"`
}

EngineSpec contains declarative configuration for the API engine. This spec is serializable and represents API-level metadata used for OpenAPI generation and documentation.

func DefaultEngineSpec

func DefaultEngineSpec() *EngineSpec

DefaultEngineSpec returns an EngineSpec with sensible defaults.

type Entryable

type Entryable interface {
	OnEntry(ctx context.Context) error
}

Entryable is implemented by input types that transform themselves before handler execution. Hooks run after body parsing and validation, before the handler function.

type Error

type Error[D any] struct {
	// contains filtered or unexported fields
}

Error represents a structured API error with code, status, message, and typed details. The type parameter D captures the details type at compile time for type-safe usage and OpenAPI schema generation.

func NewError

func NewError[D any](code string, status int, message string) *Error[D]

NewError creates a new error definition with the given code, status, and message. The type parameter D specifies the details struct type for this error. Use this to define custom error types with typed details.

func (*Error[D]) Code

func (e *Error[D]) Code() string

Code returns the error code (e.g., "NOT_FOUND").

func (*Error[D]) Details

func (e *Error[D]) Details() D

Details returns the typed error details.

func (*Error[D]) DetailsAny

func (e *Error[D]) DetailsAny() any

DetailsAny returns the error details as any for serialization. This satisfies the ErrorDefinition interface.

func (*Error[D]) DetailsMeta

func (e *Error[D]) DetailsMeta() sentinel.Metadata

DetailsMeta returns the sentinel metadata for the details type. Used by OpenAPI generation to create schemas.

func (*Error[D]) Error

func (e *Error[D]) Error() string

Error implements the error interface.

func (*Error[D]) Is

func (e *Error[D]) Is(target error) bool

Is enables errors.Is() to match against base error codes. Two errors match if they have the same code.

func (*Error[D]) Message

func (e *Error[D]) Message() string

Message returns the human-readable error message.

func (*Error[D]) Status

func (e *Error[D]) Status() int

Status returns the HTTP status code.

func (*Error[D]) Unwrap

func (e *Error[D]) Unwrap() error

Unwrap returns the underlying cause error for error chain traversal.

func (*Error[D]) WithCause

func (e *Error[D]) WithCause(cause error) *Error[D]

WithCause returns a new error with the given underlying cause. The cause is not exposed to API clients but is available for logging/debugging. The original error is not modified (immutable).

func (*Error[D]) WithDetails

func (e *Error[D]) WithDetails(details D) *Error[D]

WithDetails returns a new error with the given typed details. The original error is not modified (immutable).

func (*Error[D]) WithMessage

func (e *Error[D]) WithMessage(message string) *Error[D]

WithMessage returns a new error with a custom message. The original error is not modified (immutable).

type ErrorDefinition

type ErrorDefinition interface {
	error
	Code() string
	Status() int
	Message() string
	DetailsAny() any                // For serialization (type-erased)
	DetailsMeta() sentinel.Metadata // For OpenAPI schema generation
}

ErrorDefinition is the interface that all error definitions satisfy. It provides non-generic access to error metadata for the engine and OpenAPI generation.

type Event

type Event struct {
	// Event identification
	Type      string    // Event type (e.g., "request.received", "worker.started")
	Timestamp time.Time // When this event occurred

	// Request context (immutable snapshot)
	Method string // HTTP method
	Path   string // Request path
	Host   string // Request host

	// Processing state (snapshot at event time)
	Status   int            // HTTP status code
	Error    string         // Error message if any
	Metadata map[string]any // Event-specific metadata

	// System context
	WorkerID    int     // Worker processing this request (-1 if N/A)
	QueueDepth  int     // Queue depth at event time
	QueueWaitMs float64 // Milliseconds spent in queue
	DurationMs  float64 // Processing duration in milliseconds
}

Event represents a snapshot of system state at a specific moment. Events are immutable once created and safe for async processing. They capture relevant data from Jobs and add temporal context for linear analysis in observability systems.

func NewRequestEvent

func NewRequestEvent(eventType string, r *http.Request, metadata map[string]any) *Event

NewRequestEvent creates an Event from an HTTP request and additional context. It copies relevant data to ensure immutability.

func NewSystemEvent

func NewSystemEvent(eventType string, metadata map[string]any) *Event

NewSystemEvent creates an Event for system-level events without a request. Used for shutdown events and other engine-level events.

type ForbiddenDetails

type ForbiddenDetails struct {
	Reason string `json:"reason,omitempty" description:"Why access was denied"`
}

ForbiddenDetails provides context for authorization errors.

type Handler

type Handler[In, Out any] struct {

	// Type metadata from sentinel.
	InputMeta  sentinel.Metadata
	OutputMeta sentinel.Metadata
	// contains filtered or unexported fields
}

Handler wraps a typed handler function with metadata for documentation and parsing. It implements Endpoint interface. The handler function receives a Request with typed input and parameters.

func DELETE

func DELETE[In, Out any](path string, fn func(*Request[In]) (Out, error)) *Handler[In, Out]

DELETE creates a handler for DELETE requests.

func GET

func GET[In, Out any](path string, fn func(*Request[In]) (Out, error)) *Handler[In, Out]

GET creates a handler for GET requests.

func NewHandler

func NewHandler[In, Out any](name string, method, path string, fn func(*Request[In]) (Out, error)) *Handler[In, Out]

NewHandler creates a new typed handler with sentinel metadata.

func PATCH

func PATCH[In, Out any](path string, fn func(*Request[In]) (Out, error)) *Handler[In, Out]

PATCH creates a handler for PATCH requests.

func POST

func POST[In, Out any](path string, fn func(*Request[In]) (Out, error)) *Handler[In, Out]

POST creates a handler for POST requests.

func PUT

func PUT[In, Out any](path string, fn func(*Request[In]) (Out, error)) *Handler[In, Out]

PUT creates a handler for PUT requests.

func (*Handler[In, Out]) Close

func (*Handler[In, Out]) Close() error

Close implements Endpoint.

func (*Handler[In, Out]) ErrorDefs

func (h *Handler[In, Out]) ErrorDefs() []ErrorDefinition

ErrorDefs returns the declared error definitions for this handler. Used by OpenAPI generation to extract error schemas.

func (*Handler[In, Out]) Middleware

func (h *Handler[In, Out]) Middleware() []func(http.Handler) http.Handler

Middleware implements Endpoint.

func (*Handler[In, Out]) Process

func (h *Handler[In, Out]) Process(ctx context.Context, r *http.Request, w http.ResponseWriter) (int, error)

Process implements Endpoint.

func (*Handler[In, Out]) Spec

func (h *Handler[In, Out]) Spec() HandlerSpec

Spec implements Endpoint.

func (*Handler[In, Out]) WithAuthentication

func (h *Handler[In, Out]) WithAuthentication() *Handler[In, Out]

WithAuthentication marks this handler as requiring authentication.

func (*Handler[In, Out]) WithCodec

func (h *Handler[In, Out]) WithCodec(codec Codec) *Handler[In, Out]

WithCodec sets the codec for request/response serialization. This overrides the engine's default codec for this handler.

func (*Handler[In, Out]) WithDescription

func (h *Handler[In, Out]) WithDescription(desc string) *Handler[In, Out]

WithDescription sets the OpenAPI description.

func (*Handler[In, Out]) WithErrors

func (h *Handler[In, Out]) WithErrors(errs ...ErrorDefinition) *Handler[In, Out]

WithErrors declares which errors this handler may return. Undeclared errors will be converted to 500 Internal Server Error. This is used for OpenAPI documentation generation with proper error schemas.

func (*Handler[In, Out]) WithMaxBodySize

func (h *Handler[In, Out]) WithMaxBodySize(size int64) *Handler[In, Out]

WithMaxBodySize sets the maximum request body size in bytes for this handler. Set to 0 for unlimited (not recommended for production).

func (*Handler[In, Out]) WithMiddleware

func (h *Handler[In, Out]) WithMiddleware(middleware ...func(http.Handler) http.Handler) *Handler[In, Out]

WithMiddleware adds middleware to this handler and returns the handler for chaining.

func (*Handler[In, Out]) WithName

func (h *Handler[In, Out]) WithName(name string) *Handler[In, Out]

WithName sets a custom handler name, overriding the auto-generated one. This affects the OpenAPI operationId and log entries.

func (*Handler[In, Out]) WithOutputValidation

func (h *Handler[In, Out]) WithOutputValidation() *Handler[In, Out]

WithOutputValidation enables validation of output structs before sending responses. This is disabled by default for performance. Enable in development to catch bugs early. Output validation failures return 500 Internal Server Error.

func (*Handler[In, Out]) WithPathParams

func (h *Handler[In, Out]) WithPathParams(params ...string) *Handler[In, Out]

WithPathParams specifies required path parameters.

func (*Handler[In, Out]) WithQueryParams

func (h *Handler[In, Out]) WithQueryParams(params ...string) *Handler[In, Out]

WithQueryParams specifies required query parameters.

func (*Handler[In, Out]) WithResponseHeaders

func (h *Handler[In, Out]) WithResponseHeaders(headers map[string]string) *Handler[In, Out]

WithResponseHeaders sets default response headers for this handler.

func (*Handler[In, Out]) WithRoles

func (h *Handler[In, Out]) WithRoles(roles ...string) *Handler[In, Out]

WithRoles adds a role requirement group (OR logic within group, AND across multiple calls). Example: .WithRoles("admin", "moderator") requires (admin OR moderator). Calling multiple times creates AND: .WithRoles("admin").WithRoles("verified") = admin AND verified.

func (*Handler[In, Out]) WithScopes

func (h *Handler[In, Out]) WithScopes(scopes ...string) *Handler[In, Out]

WithScopes adds a scope requirement group (OR logic within group, AND across multiple calls). Example: .WithScopes("read", "write") requires (read OR write). Calling multiple times creates AND: .WithScopes("read").WithScopes("admin") = read AND admin.

func (*Handler[In, Out]) WithSuccessStatus

func (h *Handler[In, Out]) WithSuccessStatus(status int) *Handler[In, Out]

WithSuccessStatus sets the HTTP status code for successful responses.

func (*Handler[In, Out]) WithSummary

func (h *Handler[In, Out]) WithSummary(summary string) *Handler[In, Out]

WithSummary sets the OpenAPI summary.

func (*Handler[In, Out]) WithTags

func (h *Handler[In, Out]) WithTags(tags ...string) *Handler[In, Out]

WithTags sets the OpenAPI tags.

func (*Handler[In, Out]) WithUsageLimit

func (h *Handler[In, Out]) WithUsageLimit(key string, thresholdFunc func(Identity) int) *Handler[In, Out]

WithUsageLimit adds a usage limit check based on identity stats. The handler will return 429 Too Many Requests if identity.Stats()[key] >= thresholdFunc(identity). The thresholdFunc is called with the identity to allow dynamic limits per user/tenant. Usage limits require authentication.

type HandlerSpec

type HandlerSpec struct {
	// Routing
	Name   string `json:"name" yaml:"name"`
	Method string `json:"method" yaml:"method"`
	Path   string `json:"path" yaml:"path"`

	// Documentation
	Summary     string   `json:"summary,omitempty" yaml:"summary,omitempty"`
	Description string   `json:"description,omitempty" yaml:"description,omitempty"`
	Tags        []string `json:"tags,omitempty" yaml:"tags,omitempty"`

	// Request/Response
	PathParams     []string `json:"pathParams,omitempty" yaml:"pathParams,omitempty"`
	QueryParams    []string `json:"queryParams,omitempty" yaml:"queryParams,omitempty"`
	InputTypeFQDN  string   `json:"-" yaml:"-"`
	InputTypeName  string   `json:"inputTypeName" yaml:"inputTypeName"`
	OutputTypeFQDN string   `json:"-" yaml:"-"`
	OutputTypeName string   `json:"outputTypeName" yaml:"outputTypeName"`
	SuccessStatus  int      `json:"successStatus" yaml:"successStatus"`
	ErrorCodes     []int    `json:"errorCodes,omitempty" yaml:"errorCodes,omitempty"`
	ContentType    string   `json:"contentType,omitempty" yaml:"contentType,omitempty"` // MIME type for request/response bodies

	// Authentication & Authorization
	RequiresAuth bool       `json:"requiresAuth" yaml:"requiresAuth"`
	ScopeGroups  [][]string `json:"scopeGroups,omitempty" yaml:"scopeGroups,omitempty"` // OR within group, AND across groups
	RoleGroups   [][]string `json:"roleGroups,omitempty" yaml:"roleGroups,omitempty"`   // OR within group, AND across groups

	// Rate Limiting
	UsageLimits []UsageLimit `json:"usageLimits,omitempty" yaml:"usageLimits,omitempty"`

	// Streaming
	IsStream bool `json:"isStream,omitempty" yaml:"isStream,omitempty"` // SSE stream handler
}

HandlerSpec contains declarative configuration for a route handler. This spec is serializable and represents all metadata about a handler that can be used for documentation, authorization checks, and filtering.

type Identity

type Identity interface {
	// ID returns the unique identifier for this identity (e.g., user ID, service account ID).
	ID() string

	// TenantID returns the tenant/organization this identity belongs to.
	// Return empty string if not applicable.
	TenantID() string

	// Email returns the email address associated with this identity.
	// Return empty string if not available.
	Email() string

	// Scopes returns all scopes/permissions granted to this identity.
	Scopes() []string

	// Roles returns all roles assigned to this identity.
	Roles() []string

	// HasScope checks if this identity has the given scope/permission.
	HasScope(scope string) bool

	// HasRole checks if this identity has the given role.
	HasRole(role string) bool

	// Stats returns usage metrics for rate limiting.
	// Keys are metric names (e.g., "requests_today", "api_calls_this_hour").
	// Values are current counts.
	Stats() map[string]int
}

Identity represents an authenticated user or service account. Users must implement this interface with their own identity type.

type InternalServerDetails

type InternalServerDetails struct {
	Reason string `json:"reason,omitempty" description:"Internal error context"`
}

InternalServerDetails provides context for internal errors (not exposed to clients).

type JSONCodec

type JSONCodec struct{}

JSONCodec implements Codec using encoding/json.

func (JSONCodec) ContentType

func (JSONCodec) ContentType() string

ContentType returns "application/json".

func (JSONCodec) Marshal

func (JSONCodec) Marshal(v any) ([]byte, error)

Marshal encodes v as JSON.

func (JSONCodec) Unmarshal

func (JSONCodec) Unmarshal(data []byte, v any) error

Unmarshal decodes JSON data into v.

type NoBody

type NoBody struct{}

NoBody represents an empty input for handlers that don't expect a request body. Used for GET, HEAD, DELETE requests.

type NoDetails

type NoDetails struct{}

NoDetails is used for errors that don't carry additional details.

type NoIdentity

type NoIdentity struct{}

NoIdentity represents the absence of authentication. Used for public endpoints that don't require authentication.

func (NoIdentity) Email

func (NoIdentity) Email() string

Email implements Identity.

func (NoIdentity) HasRole

func (NoIdentity) HasRole(_ string) bool

HasRole implements Identity.

func (NoIdentity) HasScope

func (NoIdentity) HasScope(_ string) bool

HasScope implements Identity.

func (NoIdentity) ID

func (NoIdentity) ID() string

ID implements Identity.

func (NoIdentity) Roles

func (NoIdentity) Roles() []string

Roles implements Identity.

func (NoIdentity) Scopes

func (NoIdentity) Scopes() []string

Scopes implements Identity.

func (NoIdentity) Stats

func (NoIdentity) Stats() map[string]int

Stats implements Identity.

func (NoIdentity) TenantID

func (NoIdentity) TenantID() string

TenantID implements Identity.

type NotFoundDetails

type NotFoundDetails struct {
	Resource string `json:"resource,omitempty" description:"The type of resource that was not found"`
}

NotFoundDetails provides context for not found errors.

type NotImplementedDetails

type NotImplementedDetails struct {
	Feature string `json:"feature,omitempty" description:"The feature that is not implemented"`
}

NotImplementedDetails provides context for not implemented errors.

type Params

type Params struct {
	Path  map[string]string // Path parameters (e.g., /users/{id})
	Query map[string]string // Query parameters (e.g., ?page=1)
}

Params holds extracted request parameters.

type PayloadTooLargeDetails

type PayloadTooLargeDetails struct {
	MaxSize int64 `json:"max_size,omitempty" description:"Maximum allowed payload size in bytes"`
}

PayloadTooLargeDetails provides context for payload size errors.

type Redirect

type Redirect struct {
	URL     string      // Target URL (required)
	Status  int         // HTTP status code (default: 302 Found)
	Headers http.Header // Additional response headers (e.g., Set-Cookie)
}

Redirect represents an HTTP redirect response. Return this from a handler to redirect the client instead of returning a body.

Headers are written to the response before the redirect. Use this to set cookies or other headers on the redirect response (e.g., Set-Cookie for sessions).

Example:

handler := rocco.GET[rocco.NoBody, rocco.Redirect]("/old-path", func(req *rocco.Request[rocco.NoBody]) (rocco.Redirect, error) {
    return rocco.Redirect{URL: "/new-path"}, nil
})

type Request

type Request[In any] struct {
	context.Context // Embedded for deadline, cancellation, values
	*http.Request   // Embedded for direct access when needed (use sparingly)
	Params          *Params
	Body            In
	Identity        Identity // Authenticated identity (nil/NoIdentity for public endpoints)
}

Request holds all data needed by handler callbacks. It embeds context and the underlying HTTP request for full access.

IMPORTANT: Modifying the embedded *http.Request (headers, etc.) is not recommended as changes won't be reflected in OpenAPI documentation or handler configuration. Use Handler builder methods (WithResponseHeaders, WithSuccessStatus) for documented behavior.

type Sendable

type Sendable interface {
	OnSend(ctx context.Context) error
}

Sendable is implemented by output types that transform themselves before marshaling. Hooks run after the handler function, before output validation and marshaling.

type ServiceUnavailableDetails

type ServiceUnavailableDetails struct {
	Reason string `json:"reason,omitempty" description:"Why the service is unavailable"`
}

ServiceUnavailableDetails provides context for service unavailable errors.

type Stream

type Stream[T any] interface {
	// Send sends a data-only event.
	Send(data T) error
	// SendEvent sends a named event with data.
	SendEvent(event string, data T) error
	// SendComment sends a comment (useful for keep-alive).
	SendComment(comment string) error
	// Done returns a channel closed when client disconnects.
	Done() <-chan struct{}
}

Stream provides a typed interface for sending SSE events.

type StreamHandler

type StreamHandler[In, Out any] struct {

	// Type metadata from sentinel.
	InputMeta  sentinel.Metadata
	OutputMeta sentinel.Metadata
	// contains filtered or unexported fields
}

StreamHandler wraps a typed streaming handler function with metadata. It implements Endpoint interface for SSE (Server-Sent Events) responses.

func NewStreamHandler

func NewStreamHandler[In, Out any](name string, method, path string, fn func(*Request[In], Stream[Out]) error) *StreamHandler[In, Out]

NewStreamHandler creates a new typed streaming handler with sentinel metadata.

func (*StreamHandler[In, Out]) Close

func (*StreamHandler[In, Out]) Close() error

Close implements Endpoint.

func (*StreamHandler[In, Out]) ErrorDefs

func (h *StreamHandler[In, Out]) ErrorDefs() []ErrorDefinition

ErrorDefs implements Endpoint.

func (*StreamHandler[In, Out]) Middleware

func (h *StreamHandler[In, Out]) Middleware() []func(http.Handler) http.Handler

Middleware implements Endpoint.

func (*StreamHandler[In, Out]) Process

func (h *StreamHandler[In, Out]) Process(ctx context.Context, r *http.Request, w http.ResponseWriter) (int, error)

Process implements Endpoint.

func (*StreamHandler[In, Out]) Spec

func (h *StreamHandler[In, Out]) Spec() HandlerSpec

Spec implements Endpoint.

func (*StreamHandler[In, Out]) WithAuthentication

func (h *StreamHandler[In, Out]) WithAuthentication() *StreamHandler[In, Out]

WithAuthentication marks this handler as requiring authentication.

func (*StreamHandler[In, Out]) WithDescription

func (h *StreamHandler[In, Out]) WithDescription(desc string) *StreamHandler[In, Out]

WithDescription sets the OpenAPI description.

func (*StreamHandler[In, Out]) WithErrors

func (h *StreamHandler[In, Out]) WithErrors(errs ...ErrorDefinition) *StreamHandler[In, Out]

WithErrors declares which errors this handler may return. Note: Errors can only be returned before the stream starts.

func (*StreamHandler[In, Out]) WithMiddleware

func (h *StreamHandler[In, Out]) WithMiddleware(middleware ...func(http.Handler) http.Handler) *StreamHandler[In, Out]

WithMiddleware adds middleware to this handler.

func (*StreamHandler[In, Out]) WithPathParams

func (h *StreamHandler[In, Out]) WithPathParams(params ...string) *StreamHandler[In, Out]

WithPathParams specifies required path parameters.

func (*StreamHandler[In, Out]) WithQueryParams

func (h *StreamHandler[In, Out]) WithQueryParams(params ...string) *StreamHandler[In, Out]

WithQueryParams specifies required query parameters.

func (*StreamHandler[In, Out]) WithRoles

func (h *StreamHandler[In, Out]) WithRoles(roles ...string) *StreamHandler[In, Out]

WithRoles adds a role requirement group.

func (*StreamHandler[In, Out]) WithScopes

func (h *StreamHandler[In, Out]) WithScopes(scopes ...string) *StreamHandler[In, Out]

WithScopes adds a scope requirement group.

func (*StreamHandler[In, Out]) WithSummary

func (h *StreamHandler[In, Out]) WithSummary(summary string) *StreamHandler[In, Out]

WithSummary sets the OpenAPI summary.

func (*StreamHandler[In, Out]) WithTags

func (h *StreamHandler[In, Out]) WithTags(tags ...string) *StreamHandler[In, Out]

WithTags sets the OpenAPI tags.

type TooManyRequestsDetails

type TooManyRequestsDetails struct {
	RetryAfter int `json:"retry_after,omitempty" description:"Seconds until the client can retry"`
}

TooManyRequestsDetails provides context for rate limit errors.

type UnauthorizedDetails

type UnauthorizedDetails struct {
	Reason string `json:"reason,omitempty" description:"Why authentication failed"`
}

UnauthorizedDetails provides context for authentication errors.

type UnprocessableEntityDetails

type UnprocessableEntityDetails struct {
	Reason string `json:"reason,omitempty" description:"Why the entity was unprocessable"`
}

UnprocessableEntityDetails provides context for validation errors.

type UsageLimit

type UsageLimit struct {
	Key           string             // Stats key to check (e.g., "requests_today")
	ThresholdFunc func(Identity) int // Function that returns threshold for this identity
}

UsageLimit represents a usage limit check with a dynamic threshold callback.

type Validatable

type Validatable interface {
	Validate() error
}

Validatable is implemented by types that can validate themselves. Input and output structs can implement this interface to opt-in to validation.

type ValidationDetails

type ValidationDetails struct {
	Fields []ValidationFieldError `json:"fields" description:"List of validation errors"`
}

ValidationDetails provides detailed validation errors for request validation. Implements error interface for use with errors.As().

func (ValidationDetails) Error

func (v ValidationDetails) Error() string

Error implements the error interface.

type ValidationFieldError

type ValidationFieldError struct {
	Field   string `json:"field" description:"The field that failed validation"`
	Message string `json:"message" description:"Description of the validation failure"`
}

ValidationFieldError represents a single field validation error.

Directories

Path Synopsis
Package oauth provides OAuth 2.0 protocol functions for the authorization code flow.
Package oauth provides OAuth 2.0 protocol functions for the authorization code flow.
Package session provides cookie-based session management for rocco APIs.
Package session provides cookie-based session management for rocco APIs.
Package testing provides test utilities for rocco.
Package testing provides test utilities for rocco.

Jump to

Keyboard shortcuts

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