api

package module
v0.0.0-...-f93009d Latest Latest
Warning

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

Go to latest
Published: Aug 20, 2025 License: MIT Imports: 24 Imported by: 1

README

pkg/api - Convention Over Configuration HTTP Handler

codecov

This package provides a Convention Over Configuration HTTP handler adapter that uses structured request types to eliminate the need for parameter location tags.

Installation

go get github.com/gork-labs/gork/pkg/api

Convention Over Configuration

Instead of using tags to specify parameter locations, use structured request types with standard sections: Query, Body, Path, Headers, and Cookies.

Basic Example
package main

import (
    "context"
    "net/http"
    "github.com/gork-labs/gork/pkg/api"
)

// User represents the user data structure
type User struct {
    // ID is the unique identifier for the user
    ID    string `gork:"id"`
    // Name is the user's full name
    Name  string `gork:"name"`
    // Email is the user's email address
    Email string `gork:"email"`
}

// Convention Over Configuration request structure
type CreateUserRequest struct {
    Body struct {
        // Name is the user's full name
        Name  string `gork:"name" validate:"required,min=3"`
        // Email is the user's email address
        Email string `gork:"email" validate:"required,email"`
    }
}

type CreateUserResponse struct {
    Body User
}

// Implement your business logic
func CreateUser(ctx context.Context, req CreateUserRequest) (*CreateUserResponse, error) {
    return &CreateUserResponse{
        Body: User{
            ID:    "user-123",
            Name:  req.Body.Name,
            Email: req.Body.Email,
        },
    }, nil
}

func main() {
    // Create convention handler
    factory := api.NewConventionHandlerFactory()
    adapter := &api.HTTPParameterAdapter{}
    handler, _ := factory.CreateHandler(adapter, CreateUser)
    
    http.HandleFunc("/users", handler)
    http.ListenAndServe(":8080", nil)
}
Error Handling

The adapter automatically handles errors and returns appropriate HTTP responses:

func GetUser(ctx context.Context, req GetUserRequest) (*GetUserResponse, error) {
    user, err := db.GetUser(req.Path.ID)
    if err != nil {
        if errors.Is(err, ErrNotFound) {
            return nil, &api.ErrorResponse{Error: "User not found"}
        }
        return nil, err // 500 Internal Server Error
    }
    return &GetUserResponse{Body: user}, nil
}
Request Structure

Use structured sections to organize parameters by their HTTP location:

type UpdateUserRequest struct {
    Path struct {
        // UserID is the unique identifier for the user to update
        UserID string `gork:"user_id" validate:"required,uuid"`
    }
    Query struct {
        // Notify determines if notifications should be sent
        Notify bool `gork:"notify"`
    }
    Headers struct {
        // Version specifies the API version for the request
        Version int `gork:"X-User-Version"`
    }
    Body struct {
        // Name is the updated user's full name
        Name  string `gork:"name" validate:"omitempty,min=3,max=100"`
        // Email is the updated user's email address
        Email string `gork:"email" validate:"omitempty,email"`
    }
}
Mixed Parameter Example

All parameter types in one request:

// POST /users/123?notify=true
// Headers: X-User-Version: 2
// Body: {"name": "John", "email": "[email protected]"}

type UpdateUserRequest struct {
    Path struct {
        // UserID comes from the URL path parameter
        UserID string `gork:"user_id"`
    }
    Query struct {
        // Notify comes from the query string
        Notify bool `gork:"notify"`
    }
    Headers struct {
        // Version comes from HTTP headers
        Version int `gork:"X-User-Version"`
    }
    Body struct {
        // Name comes from the JSON request body
        Name  string `gork:"name"`
        // Email comes from the JSON request body
        Email string `gork:"email"`
    }
}
Context Usage

The adapter passes through the HTTP request context:

func GetUser(ctx context.Context, req GetUserRequest) (*GetUserResponse, error) {
    // Access request-scoped values
    userID := ctx.Value("userID").(string)
    
    // Use context for cancellation
    select {
    case <-ctx.Done():
        return nil, ctx.Err()
    default:
        // Continue processing
    }
    
    return fetchUser(ctx, req.Path.ID)
}

Features

  • Convention Over Configuration: No need for parameter location tags
  • Type Safety: Compile-time type checking for requests and responses
  • Automatic Validation: Built-in request validation using gork tags
  • Error Handling: Consistent error responses with proper HTTP status codes
  • Structured Requests: Clear separation of parameters by HTTP location
  • Context Propagation: Full support for context cancellation and values
  • Framework Agnostic: Works with any router that accepts http.HandlerFunc

Handler Signature

Handlers must follow this signature:

func HandlerName(ctx context.Context, req RequestType) (*ResponseType, error)

Where:

  • ctx is the request context
  • req is your request type with convention sections (validated automatically)
  • ResponseType is your response type with convention sections (pointer)
  • error is for error handling

OpenAPI Integration

This adapter automatically generates OpenAPI specifications from convention-based request/response structures using the gork CLI tool.

Examples

See the examples directory for complete working examples with different web frameworks.

License

MIT License - see the root LICENSE file for details.

Documentation

Overview

Package api provides HTTP handler wrappers and OpenAPI generation capabilities.

Index

Constants

View Source
const (
	SectionQuery   = "Query"
	SectionBody    = "Body"
	SectionPath    = "Path"
	SectionHeaders = "Headers"
	SectionCookies = "Cookies"
)

Standard section names as defined in the Convention Over Configuration spec.

Variables

AllowedSections defines the valid section names.

Functions

func CheckDiscriminatorErrors

func CheckDiscriminatorErrors(v interface{}) map[string][]string

CheckDiscriminatorErrors inspects v (struct pointer or struct) for fields carrying a `gork:"field_name,discriminator=<value>"` tag and returns a map of field names -> slice of validation error codes. The returned slice will contain either "required" (when the field is empty) or "discriminator" (when value does not match the expected discriminator constant).

The map format matches ValidationErrorResponse.Details to plug directly into response rendering.

func EnhanceOpenAPISpecWithDocs

func EnhanceOpenAPISpecWithDocs(spec *OpenAPISpec, extractor *DocExtractor)

EnhanceOpenAPISpecWithDocs enriches an already generated specification with documentation extracted from source code. It can be used when the spec was produced by a separate process (e.g. a runtime export) and therefore we no longer have access to the RouteRegistry.

func GetOriginalWebhookHandler

func GetOriginalWebhookHandler(handler interface{}) interface{}

GetOriginalWebhookHandler extracts the original webhook handler from a handler function.

func IsValidationError

func IsValidationError(err error) bool

IsValidationError checks if an error is a client validation error (HTTP 400).

func NewValidator

func NewValidator(config ValidatorConfig) *validator.Validate

NewValidator creates a new validator instance with the given configuration.

func ParseRequest

func ParseRequest(r *http.Request, reqPtr interface{}) error

ParseRequest provides a public API for parsing HTTP requests using convention over configuration. This is the main entry point for webhook handlers and other use cases that need request parsing.

func SetExportConfig

func SetExportConfig(config ExportConfig)

SetExportConfig allows setting a custom export configuration for testing.

func WebhookHandlerFunc

func WebhookHandlerFunc[T WebhookRequest](handler WebhookHandler[T], opts ...WebhookOption) http.HandlerFunc

WebhookHandlerFunc creates an HTTP handler from a webhook handler using conventional request parsing.

Types

type ArrayTypeHandler

type ArrayTypeHandler struct{}

ArrayTypeHandler handles slice and array types.

func (*ArrayTypeHandler) CanHandle

func (a *ArrayTypeHandler) CanHandle(t reflect.Type) bool

CanHandle returns true if this handler can process the given type.

func (*ArrayTypeHandler) GenerateSchema

func (a *ArrayTypeHandler) GenerateSchema(t reflect.Type, registry map[string]*Schema, _ bool) *Schema

GenerateSchema generates a schema for array and slice types.

type BasicTypeHandler

type BasicTypeHandler struct{}

BasicTypeHandler handles basic types (string, int, etc.).

func (*BasicTypeHandler) CanHandle

func (b *BasicTypeHandler) CanHandle(_ reflect.Type) bool

CanHandle returns true if this handler can process the given type.

func (*BasicTypeHandler) GenerateSchema

func (b *BasicTypeHandler) GenerateSchema(t reflect.Type, registry map[string]*Schema, _ bool) *Schema

GenerateSchema generates a schema for basic types.

type BasicTypeMapper

type BasicTypeMapper interface {
	MapType(reflect.Kind) *Schema
}

BasicTypeMapper defines the interface for mapping Go types to OpenAPI schemas.

type BodyValidationError

type BodyValidationError struct {
	Errors []string `json:"errors"`
}

BodyValidationError represents validation errors that occur in the request body.

func (*BodyValidationError) Error

func (e *BodyValidationError) Error() string

func (*BodyValidationError) GetErrors

func (e *BodyValidationError) GetErrors() []string

GetErrors returns the validation errors for the body.

type Components

type Components struct {
	Schemas         map[string]*Schema         `json:"schemas,omitempty"`
	SecuritySchemes map[string]*SecurityScheme `json:"securitySchemes,omitempty"`
	Responses       map[string]*Response       `json:"responses,omitempty"`
}

Components represents the OpenAPI components section containing reusable objects.

type ContextValidator

type ContextValidator interface {
	Validate(ctx context.Context) error
}

ContextValidator interface for custom validation with access to context. Useful for webhook validation that needs to access configured secrets from context.

type ConventionHandlerFactory

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

ConventionHandlerFactory creates HTTP handlers using the Convention Over Configuration approach.

func NewConventionHandlerFactory

func NewConventionHandlerFactory() *ConventionHandlerFactory

NewConventionHandlerFactory creates a new convention handler factory.

func (*ConventionHandlerFactory) CreateHandler

func (f *ConventionHandlerFactory) CreateHandler(adapter GenericParameterAdapter[*http.Request], handler any, opts ...Option) (http.HandlerFunc, *RouteInfo)

CreateHandler creates an HTTP handler using the Convention Over Configuration approach.

func (*ConventionHandlerFactory) RegisterTypeParser

func (f *ConventionHandlerFactory) RegisterTypeParser(parserFunc any) error

RegisterTypeParser registers a type parser for complex types.

type ConventionOpenAPIGenerator

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

ConventionOpenAPIGenerator generates OpenAPI specs for Convention Over Configuration handlers.

func NewConventionOpenAPIGenerator

func NewConventionOpenAPIGenerator(spec *OpenAPISpec, extractor *DocExtractor) *ConventionOpenAPIGenerator

NewConventionOpenAPIGenerator creates a new convention OpenAPI generator.

type ConventionParser

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

ConventionParser handles parsing requests using the Convention Over Configuration approach.

func NewConventionParser

func NewConventionParser() *ConventionParser

NewConventionParser creates a new convention parser.

func (*ConventionParser) ParseRequest

func (p *ConventionParser) ParseRequest(ctx context.Context, r *http.Request, reqPtr reflect.Value, adapter GenericParameterAdapter[*http.Request]) error

ParseRequest parses an HTTP request into the given request struct using convention over configuration. Follows spec parsing order: Path, Query, Headers, Cookies, Body.

func (*ConventionParser) RegisterTypeParser

func (p *ConventionParser) RegisterTypeParser(parserFunc interface{}) error

RegisterTypeParser registers a type parser function.

type ConventionValidator

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

ConventionValidator handles validation for the Convention Over Configuration approach.

func NewConventionValidator

func NewConventionValidator() *ConventionValidator

NewConventionValidator creates a new convention validator.

func (*ConventionValidator) ValidateRequest

func (v *ConventionValidator) ValidateRequest(ctx context.Context, reqPtr interface{}) error

ValidateRequest validates a request using the Convention Over Configuration approach.

type CookiesValidationError

type CookiesValidationError struct {
	Errors []string `json:"errors"`
}

CookiesValidationError represents validation errors that occur in request cookies.

func (*CookiesValidationError) Error

func (e *CookiesValidationError) Error() string

func (*CookiesValidationError) GetErrors

func (e *CookiesValidationError) GetErrors() []string

GetErrors returns the validation errors for the cookies.

type DefaultParameterAdapter

type DefaultParameterAdapter struct{}

DefaultParameterAdapter provides basic parameter extraction from http.Request without framework-specific functionality. Used by the public ParseRequest API.

func NewDefaultParameterAdapter

func NewDefaultParameterAdapter() *DefaultParameterAdapter

NewDefaultParameterAdapter creates a new default parameter adapter.

func (*DefaultParameterAdapter) Cookie

func (d *DefaultParameterAdapter) Cookie(r *http.Request, key string) (string, bool)

Cookie extracts cookies from the request.

func (*DefaultParameterAdapter) Header

func (d *DefaultParameterAdapter) Header(r *http.Request, key string) (string, bool)

Header extracts headers from the request.

func (*DefaultParameterAdapter) Path

Path extracts path parameters - limited without framework router.

func (*DefaultParameterAdapter) Query

func (d *DefaultParameterAdapter) Query(r *http.Request, key string) (string, bool)

Query extracts query parameters from the URL.

type Discriminator

type Discriminator struct {
	PropertyName string            `json:"propertyName"`
	Mapping      map[string]string `json:"mapping,omitempty"`
}

Discriminator represents an OpenAPI discriminator object for polymorphic schemas.

type DocExtractor

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

DocExtractor parses Go source files and indexes doc comments for later lookup by name.

func NewDocExtractor

func NewDocExtractor() *DocExtractor

NewDocExtractor allocates a new instance.

func (*DocExtractor) ExtractFunctionDoc

func (d *DocExtractor) ExtractFunctionDoc(funcName string) Documentation

ExtractFunctionDoc returns the extracted documentation for the given function name.

func (*DocExtractor) ExtractTypeDoc

func (d *DocExtractor) ExtractTypeDoc(typeName string) Documentation

ExtractTypeDoc returns the extracted documentation for the given type name.

func (*DocExtractor) GetAllTypeNames

func (d *DocExtractor) GetAllTypeNames() []string

GetAllTypeNames returns all type names that have documentation.

func (*DocExtractor) ParseDirectory

func (d *DocExtractor) ParseDirectory(dir string) error

ParseDirectory walks through the provided directory (recursively) and parses every Go file it finds. It ignores vendor directories.

type DocsConfig

type DocsConfig struct {
	// Title shown in the browser tab / UI header.
	Title string
	// OpenAPIPath under which the generated OpenAPI document is served. Must start with "/".
	// Defaults to "/openapi.json".
	OpenAPIPath string
	// SpecFile points to a pre-generated OpenAPI 3.1 JSON (or YAML) file on
	// disk. When set, DocsRoute will load the specification from this file
	// once during server start-up and serve it at runtime instead of
	// generating a fresh spec on every request. This allows enrichment from
	// build-time tooling (e.g. doc comments).
	//
	// If the file cannot be read or parsed the router falls back to runtime
	// generation so that documentation is still available albeit without the
	// additional metadata.
	SpecFile string
	// UITemplate holds the HTML page used to render the documentation UI. The
	// template must contain the placeholders {{.Title}}, {{.OpenAPIPath}} and
	// {{.BasePath}} which are replaced at runtime. Predefined templates are
	// provided – StoplightUITemplate (default), SwaggerUITemplate and
	// RedocUITemplate – but callers can supply any custom template string.
	UITemplate UITemplate
}

DocsConfig holds basic configuration for documentation UI. This is intentionally minimal to keep the initial implementation lightweight. Additional fields can be added later without breaking callers.

func PrepareDocsConfig

func PrepareDocsConfig(cfg ...DocsConfig) DocsConfig

PrepareDocsConfig prepares the documentation configuration with defaults applied.

type Documentation

type Documentation struct {
	Description string
	Fields      map[string]FieldDoc
	Deprecated  bool
	Example     string
	Since       string
}

Documentation holds extracted information from Go doc comments.

type EmbeddedStructProcessor

type EmbeddedStructProcessor interface {
	ProcessEmbedded(field reflect.StructField, schema *Schema, registry map[string]*Schema) error
}

EmbeddedStructProcessor handles processing of embedded structs.

type ErrorResponse

type ErrorResponse struct {
	Error   string                 `json:"error"`
	Details map[string]interface{} `json:"details,omitempty"`
}

ErrorResponse represents a generic error response structure.

type EventHandlerFunc

type EventHandlerFunc interface{}

EventHandlerFunc is a generic interface for event handlers. Actual signature is validated at runtime and must be: func(ctx context.Context, webhookPayload *ProviderPayloadType, userPayload *UserDefinedType) error where: - ProviderPayloadType is the webhook provider's payload (e.g. *stripe.PaymentIntent) - UserDefinedType is user-defined and validated using go-playground/validator.

type ExistingTypeHandler

type ExistingTypeHandler struct{}

ExistingTypeHandler checks for already registered types.

func (*ExistingTypeHandler) CanHandle

func (e *ExistingTypeHandler) CanHandle(_ reflect.Type) bool

CanHandle returns true if this handler can process the given type.

func (*ExistingTypeHandler) GenerateSchema

func (e *ExistingTypeHandler) GenerateSchema(t reflect.Type, registry map[string]*Schema, _ bool) *Schema

GenerateSchema generates a schema for existing registered types.

type ExitFunc

type ExitFunc func(int)

ExitFunc allows dependency injection for testing.

type ExportConfig

type ExportConfig struct {
	Output    io.Writer
	ExitFunc  ExitFunc
	LogFatalf LogFatalfFunc
}

ExportConfig holds configuration for export functionality.

func DefaultExportConfig

func DefaultExportConfig() ExportConfig

DefaultExportConfig returns the default export configuration.

type ExportableRouteInfo

type ExportableRouteInfo struct {
	Method       string `json:"method"`
	Path         string `json:"path"`
	HandlerName  string `json:"handlerName"`
	RequestType  string `json:"requestType,omitempty"`
	ResponseType string `json:"responseType,omitempty"`
}

ExportableRouteInfo is a JSON-serializable version of RouteInfo without non-marshallable fields like middleware functions.

type FieldDoc

type FieldDoc struct {
	Description string
	Example     string
	Deprecated  bool
}

FieldDoc represents documentation information for a struct field.

type FieldProcessor

type FieldProcessor interface {
	ProcessField(field reflect.StructField, schema *Schema, registry map[string]*Schema) error
}

FieldProcessor handles processing of struct fields.

type FieldValidator

type FieldValidator interface {
	Var(field interface{}, tag string) error
	Struct(s interface{}) error
}

FieldValidator interface abstracts the go-playground/validator functionality for testing.

type FileReader

type FileReader interface {
	ReadFile(filename string) ([]byte, error)
}

FileReader interface for dependency injection.

type FuncForPCProvider

type FuncForPCProvider func(uintptr) *runtime.Func

FuncForPCProvider allows dependency injection for testing.

type FunctionNameExtractor

type FunctionNameExtractor func(interface{}) string

FunctionNameExtractor allows dependency injection for testing.

type GenericParameterAdapter

type GenericParameterAdapter[T any] interface {
	Path(ctx T, key string) (string, bool)
	Query(ctx T, key string) (string, bool)
	Header(ctx T, key string) (string, bool)
	Cookie(ctx T, key string) (string, bool)
}

GenericParameterAdapter works with any context type for maximum flexibility. This allows framework-specific adapters to work directly with their native context types (e.g., *fiber.Ctx, *gin.Context) without HTTP request conversion.

type GoPlaygroundValidator

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

GoPlaygroundValidator wraps the go-playground/validator to implement FieldValidator.

func (*GoPlaygroundValidator) Struct

func (g *GoPlaygroundValidator) Struct(s interface{}) error

Struct validates all fields in a struct using their validation tags.

func (*GoPlaygroundValidator) Var

func (g *GoPlaygroundValidator) Var(field interface{}, tag string) error

Var validates a single field using the provided validation tag.

type GorkTagInfo

type GorkTagInfo struct {
	Name          string
	Discriminator string
}

GorkTagInfo represents parsed gork tag information.

type HTTPParameterAdapter

type HTTPParameterAdapter struct{}

HTTPParameterAdapter implements Query, Header, and Cookie using the standard *http.Request helpers. Adapters can embed this and override Path (and any others) as needed.

func (HTTPParameterAdapter) Cookie

Cookie extracts cookie values from the HTTP request.

func (HTTPParameterAdapter) Header

Header extracts header values from the HTTP request.

func (HTTPParameterAdapter) Path

Path returns false by default – concrete adapters must override.

func (HTTPParameterAdapter) Query

Query extracts query parameters from the HTTP request.

type HandlerOption

type HandlerOption struct {
	Tags     []string
	Security []SecurityRequirement
}

HandlerOption represents an option for configuring a handler.

type Header struct {
	Description string  `json:"description,omitempty"`
	Required    bool    `json:"required,omitempty"`
	Schema      *Schema `json:"schema,omitempty"`
}

Header represents an OpenAPI header object.

type HeadersValidationError

type HeadersValidationError struct {
	Errors []string `json:"errors"`
}

HeadersValidationError represents validation errors that occur in request headers.

func (*HeadersValidationError) Error

func (e *HeadersValidationError) Error() string

func (*HeadersValidationError) GetErrors

func (e *HeadersValidationError) GetErrors() []string

GetErrors returns the validation errors for the headers.

type Info

type Info struct {
	Title   string `json:"title,omitempty"`
	Version string `json:"version,omitempty"`
}

Info represents the OpenAPI info section containing metadata about the API.

type JSONEncoder

type JSONEncoder interface {
	Encode(v interface{}) error
}

JSONEncoder interface allows dependency injection for testing.

type JSONEncoderFactory

type JSONEncoderFactory interface {
	NewEncoder(w io.Writer) JSONEncoder
}

JSONEncoderFactory creates JSON encoders.

type JSONMarshaler

type JSONMarshaler func(v any) ([]byte, error)

JSONMarshaler defines the interface for JSON marshaling.

type LogFatalfFunc

type LogFatalfFunc func(string, ...interface{})

LogFatalfFunc allows dependency injection for testing.

type MediaType

type MediaType struct {
	Schema *Schema `json:"schema,omitempty"`
}

MediaType represents an OpenAPI media type object containing schema information.

type OpenAPIOption

type OpenAPIOption func(*OpenAPISpec)

OpenAPIOption allows callers to tweak the generated specification.

func WithRouteFilter

func WithRouteFilter(f func(*RouteInfo) bool) OpenAPIOption

WithRouteFilter lets callers provide a predicate deciding whether a given RouteInfo should be included in the generated spec. Returning false skips the route. Passing this option replaces the default filter (which currently removes documentation-serving endpoints).

func WithTitle

func WithTitle(title string) OpenAPIOption

WithTitle sets the spec title.

func WithVersion

func WithVersion(version string) OpenAPIOption

WithVersion sets the spec version.

type OpenAPISpec

type OpenAPISpec struct {
	OpenAPI    string               `json:"openapi"`
	Info       Info                 `json:"info"`
	Paths      map[string]*PathItem `json:"paths"`
	Components *Components          `json:"components,omitempty"`
	// contains filtered or unexported fields
}

OpenAPISpec represents the root of an OpenAPI 3.1 document.

func GenerateOpenAPI

func GenerateOpenAPI(registry *RouteRegistry, opts ...OpenAPIOption) *OpenAPISpec

GenerateOpenAPI converts the runtime RouteRegistry into a basic OpenAPI 3.1 specification. The implementation focuses on the essential structure needed by clients; we will enrich it iteratively.

func GenerateOpenAPIWithDocs

func GenerateOpenAPIWithDocs(reg *RouteRegistry, extractor *DocExtractor, opts ...OpenAPIOption) *OpenAPISpec

GenerateOpenAPIWithDocs combines route information from the given registry with documentation parsed by DocExtractor to enrich operation and schema descriptions. The function delegates the core generation work to GenerateOpenAPI and then post-processes the specification.

func LoadStaticSpec

func LoadStaticSpec(specFile string) *OpenAPISpec

LoadStaticSpec loads an OpenAPI specification from a file.

func LoadStaticSpecWithDeps

func LoadStaticSpecWithDeps(specFile string, fileReader FileReader, parser SpecParser) *OpenAPISpec

LoadStaticSpecWithDeps loads a spec file with dependency injection.

func (*OpenAPISpec) MarshalJSON

func (s *OpenAPISpec) MarshalJSON() ([]byte, error)

MarshalJSON implements a custom marshaler for OpenAPISpec to ensure that it is always marshaled using the standard json package, even when a custom marshaler (like gork's) is active.

type Operation

type Operation struct {
	OperationID string                 `json:"operationId,omitempty"`
	Summary     string                 `json:"summary,omitempty"`
	Description string                 `json:"description,omitempty"`
	Tags        []string               `json:"tags,omitempty"`
	Security    []map[string][]string  `json:"security,omitempty"`
	Parameters  []Parameter            `json:"parameters,omitempty"`
	RequestBody *RequestBody           `json:"requestBody,omitempty"`
	Responses   map[string]*Response   `json:"responses,omitempty"`
	Deprecated  bool                   `json:"deprecated,omitempty"`
	Extensions  map[string]interface{} `json:"-"` // Custom extensions like x-webhook-provider
	// Explicit vendor extension fields to ensure emission
	XWebhookProvider map[string]string        `json:"x-webhook-provider,omitempty"`
	XWebhookEvents   []map[string]interface{} `json:"x-webhook-events,omitempty"`
}

Operation represents an OpenAPI operation object describing a single API operation.

func (*Operation) MarshalJSON

func (o *Operation) MarshalJSON() ([]byte, error)

MarshalJSON ensures Operation.Extensions are emitted as top-level x-* fields.

type Option

type Option func(*HandlerOption)

Option is a function that modifies HandlerOption.

func WithAPIKeyAuth

func WithAPIKeyAuth() Option

WithAPIKeyAuth adds API key authentication requirement.

func WithBasicAuth

func WithBasicAuth() Option

WithBasicAuth adds basic authentication requirement.

func WithBearerTokenAuth

func WithBearerTokenAuth(scopes ...string) Option

WithBearerTokenAuth adds bearer token authentication requirement.

func WithTags

func WithTags(tags ...string) Option

WithTags adds tags to the handler.

type Parameter

type Parameter struct {
	Name        string  `json:"name"`
	In          string  `json:"in"` // "query", "header", "path", "cookie"
	Required    bool    `json:"required"`
	Description string  `json:"description,omitempty"`
	Schema      *Schema `json:"schema,omitempty"`
}

Parameter represents an OpenAPI parameter object describing a single operation parameter.

type PathItem

type PathItem struct {
	Get    *Operation `json:"get,omitempty"`
	Post   *Operation `json:"post,omitempty"`
	Put    *Operation `json:"put,omitempty"`
	Patch  *Operation `json:"patch,omitempty"`
	Delete *Operation `json:"delete,omitempty"`
}

PathItem represents a path item object containing HTTP operations for a path.

type PathValidationError

type PathValidationError struct {
	Errors []string `json:"errors"`
}

PathValidationError represents validation errors that occur in path parameters.

func (*PathValidationError) Error

func (e *PathValidationError) Error() string

func (*PathValidationError) GetErrors

func (e *PathValidationError) GetErrors() []string

GetErrors returns the validation errors for the path parameters.

type PointerTypeHandler

type PointerTypeHandler struct{}

PointerTypeHandler handles pointer types.

func (*PointerTypeHandler) CanHandle

func (p *PointerTypeHandler) CanHandle(t reflect.Type) bool

CanHandle returns true if this handler can process the given type.

func (*PointerTypeHandler) GenerateSchema

func (p *PointerTypeHandler) GenerateSchema(t reflect.Type, registry map[string]*Schema, makePointerNullable bool) *Schema

GenerateSchema generates a schema for pointer types.

type QueryValidationError

type QueryValidationError struct {
	Errors []string `json:"errors"`
}

QueryValidationError represents validation errors that occur in query parameters.

func (*QueryValidationError) Error

func (e *QueryValidationError) Error() string

func (*QueryValidationError) GetErrors

func (e *QueryValidationError) GetErrors() []string

GetErrors returns the validation errors for the query parameters.

type RegisteredEventHandler

type RegisteredEventHandler struct {
	EventType           string
	HandlerFunc         EventHandlerFunc
	HandlerName         string
	ProviderPayloadType reflect.Type
	UserMetadataType    reflect.Type
}

RegisteredEventHandler captures metadata about a registered event handler for documentation.

func GetWebhookHandlersMetadata

func GetWebhookHandlersMetadata(handler http.HandlerFunc) []RegisteredEventHandler

GetWebhookHandlersMetadata returns the list of registered handlers metadata for the webhook http handler.

type RequestBody

type RequestBody struct {
	Required    bool                  `json:"required,omitempty"`
	Description string                `json:"description,omitempty"`
	Content     map[string]*MediaType `json:"content,omitempty"`
}

RequestBody represents an OpenAPI request body object.

type RequestValidationError

type RequestValidationError struct {
	Errors []string `json:"errors"`
}

RequestValidationError represents validation errors that occur at the request level.

func (*RequestValidationError) Error

func (e *RequestValidationError) Error() string

func (*RequestValidationError) GetErrors

func (e *RequestValidationError) GetErrors() []string

GetErrors returns the validation errors for the request.

type Response

type Response struct {
	Ref         string                `json:"$ref,omitempty"`
	Description string                `json:"description,omitempty"`
	Content     map[string]*MediaType `json:"content,omitempty"`
	Headers     map[string]*Header    `json:"headers,omitempty"`
}

Response represents an OpenAPI response object describing a single response from an API operation.

type RouteInfo

type RouteInfo struct {
	Method       string         // HTTP method (GET, POST, ...)
	Path         string         // Absolute route path, including any prefix
	Handler      interface{}    // The original typed handler function
	HandlerName  string         // getFunctionName(handler)
	RequestType  reflect.Type   // The concrete request struct type (non-pointer)
	ResponseType reflect.Type   // The concrete response struct type (non-pointer)
	Options      *HandlerOption // Collected handler options (tags, security, etc.)
	// WebhookHandler stores the original webhook handler instance for OpenAPI reflection.
	// This field is only set for webhook routes created with WebhookHandlerFunc.
	WebhookHandler interface{} // Original webhook handler with SuccessResponse() and ErrorResponse() methods
	// WebhookProviderInfo contains optional provider metadata exposed by the handler implementation.
	WebhookProviderInfo *WebhookProviderInfo
	// WebhookHandledEvents lists only the events that have user-registered handlers via WithEventHandler.
	WebhookHandledEvents []string
	// WebhookHandlersMeta contains detailed metadata about each registered handler for documentation.
	WebhookHandlersMeta []RegisteredEventHandler
	// Middleware can hold router specific middleware descriptors. For now we
	// simply keep them as raw Option values so that future work can refine the
	// representation without breaking the API.
	Middleware []Option
}

RouteInfo contains metadata about a registered route. Most fields are filled by the router implementation at registration time. Additional fields (Method / Path) are set by the concrete router wrapper right before the route is added to the registry.

type RouteRegistry

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

RouteRegistry stores route metadata for a single router instance. It is intentionally not shared globally so that multiple routers can be created in the same process without stepping on each other's toes.

The registry is safe for concurrent use by multiple goroutines.

func NewRouteRegistry

func NewRouteRegistry() *RouteRegistry

NewRouteRegistry creates a new, empty registry.

func (*RouteRegistry) Export

func (r *RouteRegistry) Export() ([]byte, error)

Export serialises the registered routes into JSON so that external tools can consume the information without importing Go types. The format is considered an implementation detail and MAY change between minor versions.

func (*RouteRegistry) GetRoutes

func (r *RouteRegistry) GetRoutes() []*RouteInfo

GetRoutes returns a copy of all registered routes so callers can freely modify the returned slice without affecting the internal state.

func (*RouteRegistry) Register

func (r *RouteRegistry) Register(info *RouteInfo)

Register adds a route to the registry.

type Schema

type Schema struct {
	// Title provides a human-readable name for the schema. Some documentation UIs
	// (e.g. ReDoc, Swagger UI) display this value in type signatures. We set it
	// automatically from the Go type name where available so that arrays like
	// []UserResponse are shown as array[UserResponse] instead of array[object].
	Title         string             `json:"title,omitempty"`
	Ref           string             `json:"$ref,omitempty"`
	Type          string             `json:"-"`
	Types         []string           `json:"-"`
	Properties    map[string]*Schema `json:"properties,omitempty"`
	Required      []string           `json:"required,omitempty"`
	OneOf         []*Schema          `json:"oneOf,omitempty"`
	AnyOf         []*Schema          `json:"anyOf,omitempty"`
	Discriminator *Discriminator     `json:"discriminator,omitempty"`
	Description   string             `json:"description,omitempty"`
	Minimum       *float64           `json:"minimum,omitempty"`
	Maximum       *float64           `json:"maximum,omitempty"`
	MinLength     *int               `json:"minLength,omitempty"`
	MaxLength     *int               `json:"maxLength,omitempty"`
	Pattern       string             `json:"pattern,omitempty"`
	Enum          []string           `json:"enum,omitempty"`
	Items         *Schema            `json:"items,omitempty"`
	Format        string             `json:"format,omitempty"`
}

Schema represents an OpenAPI schema object defining the structure of request/response data.

func (*Schema) MarshalJSON

func (s *Schema) MarshalJSON() ([]byte, error)

MarshalJSON implements custom JSON marshaling for Schema to handle the type field correctly. If Types is set, it marshals as an array. If Type is set, it marshals as a string.

func (*Schema) UnmarshalJSON

func (s *Schema) UnmarshalJSON(data []byte) error

UnmarshalJSON implements custom JSON unmarshaling for Schema to handle the type field correctly.

type SchemaFieldSuffix

type SchemaFieldSuffix string

SchemaFieldSuffix represents the various field suffixes used in contextual schema naming.

const (
	// SchemaSuffixBody represents request/response body schemas.
	SchemaSuffixBody SchemaFieldSuffix = "Body"
	// SchemaSuffixHeaders represents request/response header schemas.
	SchemaSuffixHeaders SchemaFieldSuffix = "Headers"
	// SchemaSuffixQuery represents request query parameter schemas.
	SchemaSuffixQuery SchemaFieldSuffix = "Query"
	// SchemaSuffixPath represents request path parameter schemas.
	SchemaSuffixPath SchemaFieldSuffix = "Path"
	// SchemaSuffixCookies represents request/response cookie schemas.
	SchemaSuffixCookies SchemaFieldSuffix = "Cookies"
	// SchemaSuffixResponse represents response schemas.
	SchemaSuffixResponse SchemaFieldSuffix = "Response"
)

func (SchemaFieldSuffix) String

func (s SchemaFieldSuffix) String() string

String returns the string representation of the schema field suffix.

type SchemaGenerator

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

SchemaGenerator orchestrates schema generation using handlers.

func NewSchemaGenerator

func NewSchemaGenerator() *SchemaGenerator

NewSchemaGenerator creates a new SchemaGenerator with default handlers.

func NewSchemaGeneratorWithHandlers

func NewSchemaGeneratorWithHandlers(handlers []TypeSchemaHandler) *SchemaGenerator

NewSchemaGeneratorWithHandlers creates a SchemaGenerator with custom handlers.

func (*SchemaGenerator) GenerateSchema

func (s *SchemaGenerator) GenerateSchema(t reflect.Type, registry map[string]*Schema, makePointerNullable bool) *Schema

GenerateSchema generates a schema using the appropriate handler.

type SecurityRequirement

type SecurityRequirement struct {
	Type   string   // "basic", "bearer", "apiKey"
	Scopes []string // For OAuth2
}

SecurityRequirement represents a security requirement for an operation.

type SecurityScheme

type SecurityScheme struct {
	Type   string `json:"type"`
	In     string `json:"in,omitempty"`
	Name   string `json:"name,omitempty"`
	Scheme string `json:"scheme,omitempty"`
}

SecurityScheme represents an OpenAPI security scheme object defining authentication methods.

type SpecParser

type SpecParser interface {
	ParseJSON(data []byte) (*OpenAPISpec, error)
	ParseYAML(data []byte) (*OpenAPISpec, error)
}

SpecParser interface for parsing spec data.

type StructSchemaBuilder

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

StructSchemaBuilder builds struct schemas using dependency injection.

func NewStructSchemaBuilder

func NewStructSchemaBuilder() *StructSchemaBuilder

NewStructSchemaBuilder creates a new builder with default processors.

func NewStructSchemaBuilderWithProcessors

func NewStructSchemaBuilderWithProcessors(
	fieldProcessor FieldProcessor,
	embeddedStructProcessor EmbeddedStructProcessor,
	typeRegistrar TypeRegistrar,
) *StructSchemaBuilder

NewStructSchemaBuilderWithProcessors creates a builder with custom processors.

func (*StructSchemaBuilder) BuildSchema

func (b *StructSchemaBuilder) BuildSchema(t reflect.Type, registry map[string]*Schema) *Schema

BuildSchema builds a schema for the given struct type.

type StructTypeHandler

type StructTypeHandler struct{}

StructTypeHandler handles struct types.

func (*StructTypeHandler) CanHandle

func (s *StructTypeHandler) CanHandle(t reflect.Type) bool

CanHandle returns true if this handler can process the given type.

func (*StructTypeHandler) GenerateSchema

func (s *StructTypeHandler) GenerateSchema(t reflect.Type, registry map[string]*Schema, _ bool) *Schema

GenerateSchema generates a schema for struct types.

type TypeDocExtractor

type TypeDocExtractor interface {
	GetAllTypeNames() []string
	ExtractTypeDoc(typeName string) Documentation
}

TypeDocExtractor defines the interface needed for enrichFromEmbeddedTypes.

type TypeParserFunc

type TypeParserFunc func(context.Context, string) (interface{}, error)

TypeParserFunc represents a type parser function with signature: func(ctx context.Context, value string) (*T, error).

type TypeParserRegistry

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

TypeParserRegistry manages type parsers for complex types.

func NewTypeParserRegistry

func NewTypeParserRegistry() *TypeParserRegistry

NewTypeParserRegistry creates a new type parser registry.

func (*TypeParserRegistry) GetParser

func (r *TypeParserRegistry) GetParser(targetType reflect.Type) TypeParserFunc

GetParser returns the parser for the given type, if registered.

func (*TypeParserRegistry) HasParser

func (r *TypeParserRegistry) HasParser(targetType reflect.Type) bool

HasParser returns true if a parser is registered for the given type.

func (*TypeParserRegistry) ListRegisteredTypes

func (r *TypeParserRegistry) ListRegisteredTypes() []reflect.Type

ListRegisteredTypes returns a list of all registered types.

func (*TypeParserRegistry) Register

func (r *TypeParserRegistry) Register(parserFunc interface{}) error

Register registers a type parser function. The function must have the signature: func(ctx context.Context, value string) (*T, error).

type TypeRegistrar

type TypeRegistrar interface {
	RegisterType(t reflect.Type, schema *Schema, registry map[string]*Schema) *Schema
}

TypeRegistrar handles registration of named types.

type TypeSchemaHandler

type TypeSchemaHandler interface {
	CanHandle(t reflect.Type) bool
	GenerateSchema(t reflect.Type, registry map[string]*Schema, makePointerNullable bool) *Schema
}

TypeSchemaHandler handles schema generation for specific types.

type TypedRouter

type TypedRouter[T any] struct {
	// contains filtered or unexported fields
}

TypedRouter provides strongly-typed methods for route registration while delegating the actual path handling to a framework-specific callback provided by the adapter wrapper.

The generic parameter `T` represents the concrete underlying router type (e.g. *http.ServeMux, *echo.Echo, …). Keeping it generic allows callers to access the underlying router without type assertions via the `Unwrap()` helper.

func NewTypedRouter

func NewTypedRouter[T any](underlying T, registry *RouteRegistry, prefix string, middleware []Option, adapter GenericParameterAdapter[*http.Request], registerFn func(method, path string, handler http.HandlerFunc, info *RouteInfo)) TypedRouter[T]

NewTypedRouter is a small helper that allocates a TypedRouter value with the provided configuration. It is exported so that adapter packages residing in sub-packages of api (e.g. adapters/stdlib) can create initialised instances without relying on internal field access.

func (*TypedRouter[T]) CopyMiddleware

func (r *TypedRouter[T]) CopyMiddleware() []Option

CopyMiddleware returns a shallow copy of the middleware slice so that router implementations can propagate it to sub-routers when creating groups.

func (*TypedRouter[T]) Delete

func (r *TypedRouter[T]) Delete(path string, handler interface{}, opts ...Option)

Delete registers a DELETE route with the given path and handler.

func (*TypedRouter[T]) DocsRoute

func (r *TypedRouter[T]) DocsRoute(path string, cfg ...DocsConfig)

DocsRoute registers (1) an endpoint that serves the generated OpenAPI spec in JSON format and (2) a catch-all route that serves a minimal HTML page loading the chosen documentation UI from a public CDN. The implementation purposefully trades customisability for a small footprint so that users can benefit from documentation immediately while we iterate on a more sophisticated solution.

func (*TypedRouter[T]) ExportOpenAPIAndExit

func (r *TypedRouter[T]) ExportOpenAPIAndExit(opts ...OpenAPIOption)

ExportOpenAPIAndExit generates an OpenAPI specification from the router's internal RouteRegistry, writes it to stdout as pretty-printed JSON and then terminates the process with exit code 0.

This function always exports and exits when called. Users should call it only when they want to export the OpenAPI specification (e.g., when GORK_EXPORT=1 environment variable is set).

func (*TypedRouter[T]) Get

func (r *TypedRouter[T]) Get(path string, handler interface{}, opts ...Option)

Get registers a GET route with the given path and handler.

func (*TypedRouter[T]) GetRegistry

func (r *TypedRouter[T]) GetRegistry() *RouteRegistry

GetRegistry satisfies the Router contract for wrappers that embed TypedRouter.

func (*TypedRouter[T]) Patch

func (r *TypedRouter[T]) Patch(path string, handler interface{}, opts ...Option)

Patch registers a PATCH route with the given path and handler.

func (*TypedRouter[T]) Post

func (r *TypedRouter[T]) Post(path string, handler interface{}, opts ...Option)

Post registers a POST route with the given path and handler.

func (*TypedRouter[T]) Put

func (r *TypedRouter[T]) Put(path string, handler interface{}, opts ...Option)

Put registers a PUT route with the given path and handler.

func (*TypedRouter[T]) Register

func (r *TypedRouter[T]) Register(method, path string, handler interface{}, opts ...Option)

Register registers a route with the given HTTP method, path and handler. The method parameter should be a standard HTTP method like "GET", "POST", "PUT", "DELETE", "PATCH", etc.

The handler parameter should be a function with the signature: func(context.Context, RequestType) (ResponseType, error)

Note: Until Go supports method-level type parameters on non-generic receivers in a stable release, we expose untyped registration helpers. These still provide compile-time safety because callers must pass a function that matches the expected signature. We perform a runtime check to be safe.

func (*TypedRouter[T]) Unwrap

func (r *TypedRouter[T]) Unwrap() T

Unwrap returns the underlying router value.

type UITemplate

type UITemplate string

UITemplate represents an HTML page template for serving API documentation. It is defined as a distinct type to avoid accidental mix-ups with regular strings and to make the purpose explicit.

const RedocUITemplate UITemplate = `` /* 379-byte string literal not displayed */

RedocUITemplate uses Redoc to render the documentation.

const StoplightUITemplate UITemplate = `` /* 483-byte string literal not displayed */

StoplightUITemplate is the default UI powered by Stoplight Elements.

const SwaggerUITemplate UITemplate = `` /* 711-byte string literal not displayed */

SwaggerUITemplate exposes the popular Swagger UI.

type UnionTypeHandler

type UnionTypeHandler struct{}

UnionTypeHandler handles union types.

func (*UnionTypeHandler) CanHandle

func (u *UnionTypeHandler) CanHandle(t reflect.Type) bool

CanHandle returns true if this handler can process the given type.

func (*UnionTypeHandler) GenerateSchema

func (u *UnionTypeHandler) GenerateSchema(t reflect.Type, registry map[string]*Schema, _ bool) *Schema

GenerateSchema generates a schema for union types.

type ValidationError

type ValidationError interface {
	error
	GetErrors() []string
}

ValidationError represents any validation error that should return HTTP 400. These errors contain client-side validation issues.

type ValidationErrorResponse

type ValidationErrorResponse struct {
	Message string              `json:"error"`
	Details map[string][]string `json:"details,omitempty"`
}

ValidationErrorResponse represents validation error responses with field-level details.

func (*ValidationErrorResponse) Error

func (v *ValidationErrorResponse) Error() string

Error implements the error interface for ValidationErrorResponse.

type Validator

type Validator interface {
	Validate() error
}

Validator interface for custom validation.

type ValidatorConfig

type ValidatorConfig struct {
	TagNameFunc func(reflect.StructField) string
}

ValidatorConfig allows for dependency injection of validator behavior.

func DefaultValidatorConfig

func DefaultValidatorConfig() ValidatorConfig

DefaultValidatorConfig returns the default validator configuration.

type WebhookEvent

type WebhookEvent struct {
	Type           string
	ProviderObject interface{}
	UserMetaJSON   json.RawMessage
}

WebhookEvent represents a verified and parsed webhook event. ProviderObject is a concrete provider payload (e.g., *stripe.PaymentIntent). UserMetaJSON optionally contains provider-extracted metadata for user validation.

type WebhookHandler

type WebhookHandler[T WebhookRequest] interface {
	// ParseRequest verifies the webhook signature and extracts event data using conventional struct
	ParseRequest(req T) (WebhookEvent, error)

	// SuccessResponse returns the appropriate success response for the provider
	SuccessResponse() interface{}

	// ErrorResponse returns the appropriate error response for the provider
	ErrorResponse(err error) interface{}

	// GetValidEventTypes returns a list of valid event types for validation and OpenAPI.
	GetValidEventTypes() []string

	// ProviderInfo exposes provider name and documentation metadata.
	ProviderInfo() WebhookProviderInfo
}

WebhookHandler defines the interface for webhook providers. T must be a type that implements WebhookRequest. All providers MUST implement ProviderInfo() to expose basic metadata.

type WebhookHandlerOption

type WebhookHandlerOption struct {
	EventHandlers map[string]EventHandlerFunc
	// When true: user metadata validation/unmarshal errors produce 400 with ErrorResponse.
	// When false (default): handlers receive a nil user metadata pointer on validation errors.
	StrictUserValidation bool
}

WebhookHandlerOption extends handler configuration with webhook-specific fields.

type WebhookOption

type WebhookOption func(*WebhookHandlerOption)

WebhookOption is a function that configures WebhookHandlerOption.

func WithEventHandler

func WithEventHandler[P any, U any](eventType string, handler func(context.Context, *P, *U) error) WebhookOption

WithEventHandler registers a type-safe handler for a specific event type. P is the provider payload type (e.g., *stripe.PaymentIntent), U is the user metadata type. Handlers are error-only; successful processing results in provider SuccessResponse.

type WebhookProviderInfo

type WebhookProviderInfo struct {
	Name    string
	Website string
	DocsURL string
}

WebhookProviderInfo describes the webhook provider metadata for documentation.

func GetWebhookRouteMetadata

func GetWebhookRouteMetadata(handler http.HandlerFunc) (*WebhookProviderInfo, []string)

GetWebhookRouteMetadata returns provider info and handled events for a registered webhook handler.

type WebhookRequest

type WebhookRequest interface {
	// WebhookRequest marker method to identify webhook request types
	WebhookRequest()
}

WebhookRequest defines the conventional request structure for webhooks. This is a marker interface that webhook request types must implement.

Directories

Path Synopsis
Package docs provides documentation extraction utilities for Go types and fields.
Package docs provides documentation extraction utilities for Go types and fields.
webhooks
fake
Package fake provides minimal webhook types for testing provider detection.
Package fake provides minimal webhook types for testing provider detection.

Jump to

Keyboard shortcuts

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