v3

package module
v1.0.1 Latest Latest
Warning

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

Go to latest
Published: Feb 25, 2026 License: Apache-2.0 Imports: 6 Imported by: 0

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

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):

  1. DiagAttachEmptyRegistry
  2. DiagBuildJSONFailed
  3. DiagDocsPathNoProvider
  4. DiagUIProviderPanicked (if the provider panics)
  5. Provider-returned diagnostics (appended in provider-defined order)

func Build

func Build(snap adapter.RegistrySnapshot, cfg Config) (Document, []Diagnostic)

func BuildJSON

func BuildJSON(doc Document) ([]byte, error)

func OperationID

func OperationID(method, fullPath string) string

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 Attached

type Attached struct {
	JSONPath string
	Doc      Document
	JSON     []byte
}

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.

https://spec.openapis.org/oas/v3.2.0#openapi-object

type Info

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

Info holds API metadata.

https://spec.openapis.org/oas/v3.2.0#info-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.

https://spec.openapis.org/oas/v3.2.0#operation-object

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

func PathParams(fullPath string) []Parameter

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.

https://spec.openapis.org/oas/v3.2.0#path-item-object

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.

https://spec.openapis.org/oas/v3.2.0#response-object

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.

https://spec.openapis.org/oas/v3.2.0#schema-object

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.

Directories

Path Synopsis
ui
validate module

Jump to

Keyboard shortcuts

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