openapi

package
v0.28.0 Latest Latest
Warning

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

Go to latest
Published: Sep 12, 2026 License: MIT Imports: 12 Imported by: 0

Documentation

Overview

Package openapi generates an OpenAPI 3.1 document from apikit request/response types and a router.Router, with zero third-party dependencies.

Request and response schemas are derived by reflecting on the same `json` and `validate` struct tags that request.Bind[T] and request.ValidateStruct already use, so a type only needs to be described once:

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

doc := openapi.New(openapi.Info{Title: "My API", Version: "1.0.0"})
doc.Add("POST", "/users", openapi.Operation{
    Summary: "Create a user",
    Request: CreateUserReq{},
    Responses: map[int]openapi.Response{
        201: {Description: "Created", Body: User{}},
    },
})

// Fill in any route the router knows about but that Add hasn't described yet.
doc.Sync(r)

r.GetFunc("/openapi.json", doc.Handler())
r.GetFunc("/docs", doc.SwaggerUIHandler("/openapi.json"))

Cross-field and programmatic validation (request.NewValidation) is out of scope for schema generation, matching the tag engine's own documented limits.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Document

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

Document accumulates operations and renders them as an OpenAPI 3.1 JSON document. The zero value is not usable; create one with New.

A Document is safe for concurrent use: Add and Sync are typically called during startup while routes are registered, and JSON/Handler are safe to call concurrently from request goroutines afterward — the rendered JSON is cached after the first call and invalidated by Add/Sync, so repeated requests to a served spec don't re-run reflection on every hit.

func New

func New(info Info) *Document

New creates an empty Document with the given metadata.

func (*Document) Add

func (d *Document) Add(method, path string, op Operation)

Add describes one method+path operation. Calling Add again for the same method and path overwrites the previous description.

func (*Document) Handler

func (d *Document) Handler() http.HandlerFunc

Handler serves the document as "application/json".

func (*Document) JSON

func (d *Document) JSON() ([]byte, error)

JSON renders the accumulated operations as an OpenAPI 3.1 document.

func (*Document) SwaggerUIHandler

func (d *Document) SwaggerUIHandler(specURL string) http.HandlerFunc

SwaggerUIHandler serves a Swagger UI page that loads the spec from specURL — typically the path where Handler is mounted, e.g. "/openapi.json".

func (*Document) Sync

func (d *Document) Sync(r *router.Router)

Sync walks r's registered routes and adds a bare (undescribed) operation for any method+path that Add hasn't already covered, so the document never drifts out of sync with the router — every real route shows up, even before someone fills in its request/response schema with Add.

Routes registered without a specific method (Handle/HandleFunc, matching every method) have no single OpenAPI operation to represent them and are skipped.

type Info

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

Info describes the API metadata block of the document.

type Operation

type Operation struct {
	Summary     string
	Description string
	Tags        []string

	// Request, when non-nil, becomes the JSON request body schema.
	Request any

	// Params declares path/query/header parameters explicitly. Path
	// parameters present in the route pattern (e.g. "{id}") but missing here
	// are added automatically as required string parameters.
	Params []Param

	// Responses maps HTTP status code to a response description and body type.
	Responses map[int]Response
}

Operation describes a single method+path entry. Request and the values in Responses are sample instances (usually zero values, e.g. CreateUserReq{}) used only for their type — schemas are derived via reflection, never from the values themselves.

type Param

type Param struct {
	Name        string
	In          string // "path", "query", or "header"
	Required    bool
	Description string

	// Schema, when nil, defaults to a plain string schema.
	Schema *Schema
}

Param describes a single path, query, or header parameter.

type Response

type Response struct {
	Description string

	// Body, when non-nil, becomes the JSON response body schema.
	Body any
}

Response describes one entry in an operation's Responses map.

type Schema

type Schema struct {
	Ref  string `json:"$ref,omitempty"`
	Type string `json:"type,omitempty"`

	Description string `json:"description,omitempty"`
	Format      string `json:"format,omitempty"`
	Pattern     string `json:"pattern,omitempty"`

	Items      *Schema            `json:"items,omitempty"`
	Properties map[string]*Schema `json:"properties,omitempty"`
	Required   []string           `json:"required,omitempty"`

	AdditionalProperties *Schema `json:"additionalProperties,omitempty"`

	// AnyOf is populated only by MarshalJSON, to express a nullable $ref
	// (see MarshalJSON's doc comment) — it's not set directly by schema.go.
	AnyOf []*Schema `json:"anyOf,omitempty"`

	Enum []string `json:"enum,omitempty"`

	Minimum          *float64 `json:"minimum,omitempty"`
	Maximum          *float64 `json:"maximum,omitempty"`
	ExclusiveMinimum *float64 `json:"exclusiveMinimum,omitempty"`
	ExclusiveMaximum *float64 `json:"exclusiveMaximum,omitempty"`
	MinLength        *int     `json:"minLength,omitempty"`
	MaxLength        *int     `json:"maxLength,omitempty"`

	Nullable bool `json:"-"` // folded into Type as ["<type>", "null"] at marshal time
}

Schema is an OpenAPI 3.1 (JSON Schema 2020-12) schema object. Only the subset of keywords the reflection engine in schema.go actually produces is represented.

func (*Schema) MarshalJSON

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

MarshalJSON folds Nullable into the "type" keyword as ["<type>", "null"], per JSON Schema 2020-12 (OpenAPI 3.1). A nullable $ref can't express that the same way — a sibling "type" next to "$ref" isn't reliably honored by tooling — so it's wrapped as {"anyOf": [{"$ref": ...}, {"type": "null"}]} instead. Everything else marshals like a plain struct.

Jump to

Keyboard shortcuts

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