Documentation
¶
Overview ¶
Package v3 provides OpenAPI 3.2 document generation and optional docs UI mounting for jetwarp.
The typical "docs in 2 lines" happy path is to call Attach once after registering routes. Attach mounts the OpenAPI JSON document (default: "/openapi.json") and may also mount a docs UI when configured via [Config.Docs].
Diagnostics stability ¶
Diagnostics are returned from Build and Attach to support both human troubleshooting and tooling.
The stability contract is:
- Compare by DiagCode only. Codes are stable and intended for programmatic use.
- Do not compare by message text. Messages are human-oriented and may evolve.
- Ordering is deterministic: 1) Build-time diagnostics (from Build) first, 2) then Attach-time diagnostics (from Attach), 3) then any diagnostics returned by [UIProvider.Mount].
This contract is enforced by conformance-style tests in the openapi/oas3 submodule.
Index ¶
- func Attach(r RegistryRouter, cfg Config) (Attached, []Diagnostic)
- func Build(snap adapter.RegistrySnapshot, cfg Config) (Document, []Diagnostic)
- func BuildJSON(doc Document) ([]byte, error)
- func OperationID(method, fullPath string) string
- type AnyPolicy
- type Attached
- type Config
- type DiagCode
- type Diagnostic
- type DocsConfig
- type Document
- type Info
- type Operation
- type Parameter
- type PathItem
- type RegistryRouter
- type Response
- type Schema
- type UIContext
- type UIProvider
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Attach ¶
func Attach(r RegistryRouter, cfg Config) (Attached, []Diagnostic)
Attach builds an OpenAPI 3.2 document from r's registry snapshot and mounts:
- the generated JSON at Config.JSONPath (GET)
- an optional docs UI at Config.Docs.Path (provider-defined), when Config.Docs.Provider is non-nil
Safety / portability:
- Attach must not panic (portable no-panic contract). Any UI provider panic is converted into a diagnostic with code DiagUIProviderPanicked.
- Even when JSON generation fails, Attach still mounts Config.JSONPath with a minimal fallback document and emits DiagBuildJSONFailed.
Diagnostics stability:
- The returned diagnostics slice is ordered. Codes + ordering are treated as a compatibility contract (conformance-style tests assert exact codes in order).
- Diagnostic Message/Path fields are informational and may change.
Docs contract matrix (inputs → mounted endpoints + diagnostics)
Always mounted:
- GET Config.JSONPath → OpenAPI JSON (Content-Type "application/json; charset=utf-8")
Docs disabled (zero-value docs):
Inputs: - Config.Docs.Path == "" AND Config.Docs.Provider == nil Mount: - JSON endpoint only Diags: - Build(...) diags (if any), then Attach-phase diags (see “Attach-phase ordering” below)
Docs path set but provider missing (footgun):
Inputs: - Config.Docs.Path != "" AND Config.Docs.Provider == nil Mount: - JSON endpoint only (no docs endpoints) Diags: - + DiagDocsPathNoProvider (after JSON mount attempt)
Docs enabled:
Inputs:
- Config.Docs.Provider != nil
- If Config.Docs.Path is empty at call-site, defaults apply (Path becomes "/docs").
Mount:
- JSON endpoint
- Provider-defined docs endpoints rooted at DocsPath
Provider call:
- Called exactly once with UIContext{DocsPath, SpecURL, Title}
Title defaulting:
- If Docs.Title is empty and Provider is non-nil, it defaults to Config.Title.
SpecURL behavior (what the UI fetches for the JSON):
If Config.Docs.SpecURL != "" → used as-is (after TrimSpace in the provider, if it chooses)
Else Attach computes a default via specURLFromPaths(DocsPath, JSONPath) when both are absolute URL paths; otherwise it falls back to JSONPath.
Computation examples (from unit tests):
DocsPath "/docs", JSONPath "/docs/openapi.json" → "openapi.json"
DocsPath "/api/docs", JSONPath "/api/openapi.json" → "./openapi.json"
DocsPath "/api/docs", JSONPath "/openapi.json" → "././openapi.json"
DocsPath "docs" (non-absolute), JSONPath "/openapi.json" → "/openapi.json"
Practical note:
Many providers serve an index page at DocsPath + "/index.html" (e.g., Swagger UI). If your JSON is mounted outside the docs subtree, prefer setting Docs.SpecURL explicitly to an absolute path (for example: "/openapi.json") to avoid surprises with relative URL resolution.
Attach-phase diagnostic ordering (after Build(...) diagnostics):
- DiagAttachEmptyRegistry
- DiagBuildJSONFailed
- DiagDocsPathNoProvider
- DiagUIProviderPanicked (if the provider panics)
- Provider-returned diagnostics (appended in provider-defined order)
func Build ¶
func Build(snap adapter.RegistrySnapshot, cfg Config) (Document, []Diagnostic)
func OperationID ¶
OperationID produces a deterministic, camelCase operation identifier from a method and a jetwarp full path.
Format: <verb><TitleToken><TitleToken>...
Examples:
GET /users → "getUsers"
GET /users/{id} → "getUsersId"
GET /users/{id}/grades → "getUsersIdGrades"
POST /users → "postUsers"
GET /items/{id}.json → "getItemsId" (suffix stripped, param name used)
GET /api/v1/students → "getApiV1Students"
* /events → "anyEvents"
Types ¶
type AnyPolicy ¶
type AnyPolicy struct {
// Expand turns a jetwarp ANY route into a set of standard methods.
Expand bool
// StandardMethods is the expansion set, using request capitalization (typically uppercase).
// If empty, defaults are used.
StandardMethods []string
// Extension adds `x-jetwarp-any: true` on the PathItem when ANY is present.
Extension bool
}
AnyPolicy defines how jetwarp ANY routes are represented in OpenAPI.
type Config ¶
type Config struct {
Title string
Version string
// JSONPath is where Attach mounts the generated OpenAPI JSON. Default: "/openapi.json".
JSONPath string
// Docs controls optional HTML documentation mounting.
Docs DocsConfig
Any AnyPolicy
}
type DiagCode ¶
type DiagCode string
DiagCode is a stable, machine-readable identifier for an openapi/oas3 diagnostic.
Codes are part of the public contract. Tooling and tests must compare diagnostics by DiagCode, not by message text.
const ( // DiagRouteHasErrors is emitted by document building when a route record contains registration errors. DiagRouteHasErrors DiagCode = "openapi.v3.route_has_errors" DiagDuplicateExplicit DiagCode = "openapi.v3.duplicate_explicit" DiagAnySuppressed DiagCode = "openapi.v3.any_suppressed_by_explicit" // DiagBuildJSONFailed is emitted by [Attach] when marshaling the generated document fails. // Attach will still mount the JSON endpoint using a minimal fallback document payload. DiagBuildJSONFailed DiagCode = "openapi.v3.build_json_failed" // DiagAttachEmptyRegistry is emitted by [Attach] when it is called with a registry snapshot // that contains zero routes. This is a common footgun when callers attach OpenAPI before // registering routes. Attach still mounts the JSON endpoint and does not panic. DiagAttachEmptyRegistry DiagCode = "openapi.v3.attach_empty_registry" // DiagDocsPathNoProvider is emitted by [Attach] when [DocsConfig.Path] is non-empty but // [DocsConfig.Provider] is nil. In this case docs UI is not mounted. DiagDocsPathNoProvider DiagCode = "openapi.v3.attach_docs_no_provider" // DiagUIProviderPanicked is emitted by [Attach] when the configured [UIProvider] panics. // Attach recovers the panic, records this diagnostic, and continues without panicking. DiagUIProviderPanicked DiagCode = "openapi.v3.ui_provider_panicked" )
type Diagnostic ¶
type Diagnostic struct {
Code DiagCode
Message string
// Optional context for tooling.
Path string
Method string
Seq uint64
}
Diagnostic describes a non-fatal issue detected while building or attaching OpenAPI artifacts.
Stability contract:
- Code (DiagCode) is stable and suitable for programmatic checks.
- Message is human-oriented and may change over time.
- Ordering is deterministic: 1) Build-time diagnostics (from Build) are returned first in the order routes are processed. 2) Attach-time diagnostics (from Attach) follow in a fixed sequence. 3) UI provider diagnostics (returned by [UIProvider.Mount]) are appended last.
type DocsConfig ¶
type DocsConfig struct {
// Path is where docs should be mounted (e.g. "/docs").
// Empty means “don’t mount docs”.
Path string
// Provider mounts the docs UI (e.g. Swagger UI).
// If nil, docs are disabled (even if Path is set; Attach will emit a diagnostic).
Provider UIProvider
// Title is the docs page title/branding. If empty, defaults to Config.Title
// when Provider is non-nil.
Title string
// SpecURL overrides the URL the UI should fetch for the OpenAPI JSON.
// If empty, Attach computes a default from Docs.Path and Config.JSONPath.
SpecURL string
}
DocsConfig controls optional HTML documentation mounting.
Zero value disables docs mounting. DocsConfig controls optional HTML documentation mounting.
Zero value disables docs mounting.
type Document ¶
type Document struct {
OpenAPI string `json:"openapi"`
Info Info `json:"info"`
Paths map[string]PathItem `json:"paths"`
}
Document is the root OpenAPI 3.2 document object.
type Operation ¶
type Operation struct {
// OperationID is a unique string identifier for the operation.
// jetwarp derives it deterministically from method + path (see operationID in operation.go).
OperationID string `json:"operationId,omitempty"`
// Summary is a short human-readable summary of the operation.
// Populated by Level 1 annotations; empty at Level 0.
Summary string `json:"summary,omitempty"`
// Tags groups operations for tooling (Swagger UI, code generators, etc.).
// Populated by Level 1 annotations; empty at Level 0.
Tags []string `json:"tags,omitempty"`
// Parameters lists path (and eventually query/header) parameters.
// At Level 0, only path parameters extracted from the route pattern are emitted.
Parameters []Parameter `json:"parameters,omitempty"`
Deprecated bool `json:"deprecated,omitempty"`
// Responses is required by the OAS spec and always emitted.
// Level 0 emits a single "default" stub; richer schemas are a Level 2 concern.
Responses map[string]Response `json:"responses"`
}
Operation describes a single API operation on a path.
Level 0 populates OperationID, Parameters (path params only), and a stub Responses. Summary and Tags are zero-valued until Level 1 annotations are wired in.
type Parameter ¶
type Parameter struct {
Name string `json:"name"`
In string `json:"in"` // "path" | "query" | "header" | "cookie"
Required bool `json:"required,omitempty"` // path params → always true; query/header → false omitted
Schema Schema `json:"schema"`
}
Parameter describes a single operation parameter (path, query, header, or cookie).
For Level 0 (topology-only), jetwarp only produces path parameters extracted from route patterns. Query/header/cookie parameters require Level 1 annotations.
https://spec.openapis.org/oas/v3.2.0#parameter-object
func PathParams ¶
PathParams extracts path parameters from a jetwarp route pattern.
It handles:
- Pure params: /users/{id} → [{name:"id", in:"path", required:true}]
- Infix params: /items/{id}.json → [{name:"id", ...}] (prefix/suffix ignored)
- Multi-param: /users/{id}/g/{gid} → [{name:"id"}, {name:"gid"}]
Duplicate param names are deduplicated (first occurrence wins, order preserved). Returns nil when the path has no parameters (avoids a non-nil empty slice in JSON).
type PathItem ¶
type PathItem struct {
// Fixed fields — OpenAPI 3.2 includes query alongside the classic set.
Get *Operation `json:"get,omitempty"`
Put *Operation `json:"put,omitempty"`
Post *Operation `json:"post,omitempty"`
Delete *Operation `json:"delete,omitempty"`
Options *Operation `json:"options,omitempty"`
Head *Operation `json:"head,omitempty"`
Patch *Operation `json:"patch,omitempty"`
Trace *Operation `json:"trace,omitempty"`
Query *Operation `json:"query,omitempty"`
// AdditionalOperations holds non-standard verbs.
// Keys must match request capitalisation and must NOT duplicate fixed-field names.
// https://spec.openapis.org/oas/v3.2.0#fixed-fields-7
AdditionalOperations map[string]*Operation `json:"additionalOperations,omitempty"`
// XjetwarpAny marks paths that originated from a jetwarp ANY route.
XjetwarpAny bool `json:"x-jetwarp-any,omitempty"`
}
PathItem describes the operations available on a single path.
OpenAPI 3.2 adds "query" as a fixed field alongside the classic HTTP methods. Non-standard verbs (LINK, PURGE, etc.) go into AdditionalOperations.
type RegistryRouter ¶
type RegistryRouter interface {
adapter.Adapter
adapter.RegistryProvider
}
RegistryRouter is the minimum router surface Attach() needs: - route registration (adapter.Adapter) - registry snapshot (adapter.RegistryProvider).
type Response ¶
type Response struct {
Description string `json:"description"`
}
Response describes a single response from an operation.
type Schema ¶
type Schema struct {
Type string `json:"type,omitempty"`
}
Schema is a minimal OpenAPI Schema Object.
Level 0 always emits Type:"string" for path parameters. Richer schemas (format, enum, object, etc.) are a Level 1/2 concern.
type UIContext ¶
type UIContext struct {
// DocsPath is the base mount path for the UI (e.g. "/docs").
DocsPath string
// SpecURL is the URL the UI should fetch for the OpenAPI JSON.
// It may be relative or absolute.
// If empty, Attach computes a default from DocsPath and Config.JSONPath
// (see Attach for examples and the compatibility contract).
SpecURL string
// Title is a human-facing title for the UI.
Title string
}
UIContext describes where and how a docs UI should be mounted.
All fields are URL paths (no scheme/host). SpecURL may be relative.
type UIProvider ¶
type UIProvider interface {
Mount(r adapter.Adapter, ctx UIContext) []Diagnostic
}
UIProvider mounts an HTML documentation UI (e.g. Swagger UI).
Providers must not panic. Attach will convert panics into diagnostics, but providers should still avoid panics to keep diagnostics clean.