openapi

package
v1.23.1 Latest Latest
Warning

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

Go to latest
Published: Jun 23, 2026 License: MIT Imports: 11 Imported by: 0

Documentation

Overview

Package openapi auto-generates an OpenAPI 3.1 specification from the framework's typed registry and serves it (plus Swagger UI) from a nexus app. Zero hand-written spec, always in sync with the running app.

Wire it up next to your other modules. The plugin reads from the client manifest (which the framework already builds from reflection) and emits an OpenAPI document on demand. No build step, no codegen invocation.

import "github.com/paulmanoni/nexus/extension/openapi"

nexus.Run(
    nexus.Config{
        Server: nexus.ServerConfig{Addr: ":8080"},
        Client: client.Config{Enabled: true}, // the plugin reads from here
    },
    openapi.Plugin(openapi.Config{
        Title:       "Pet Shop API",
        Version:     "1.0.0",
        Description: "Catalog + orders + waitlist",
    }),
    // ... rest of the app
)

What the plugin exposes:

GET /__nexus/openapi/spec.json   — the spec (JSON, primary)
GET /__nexus/openapi/spec.yaml   — same spec, YAML encoding
GET /__nexus/openapi/ui          — Swagger UI HTML, loads spec.json

And, when Config.PublicRoot is true (the default), additional routes at the API root so customer-facing tooling finds them at the conventional paths:

GET /openapi.json
GET /api-docs              — Swagger UI

Customers run `openapi-generator-cli` against /openapi.json and get a typed client SDK in any language. The same spec drives Postman collections, Schemathesis fuzzing, Spectral linting.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Plugin

func Plugin(cfg Config) nexus.Option

Plugin wires the OpenAPI generator into the app's plugin chain. Generation runs lazily at request time so a freshly-added endpoint shows up in /spec.json without a restart (the live registry is the source). On a stable production app the overhead is one map walk per request; for higher throughput we could cache and invalidate on registry.OnChange, but that's premature for the v1 size.

Types

type Components

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

Components houses reusable schemas + security definitions. The nexus generator only populates Schemas (from registry.Refs) and SecuritySchemes (from auth.ExtractorInfo).

type Config

type Config struct {
	// Title is the API name that appears in info.title. Defaults to
	// "Nexus API" if empty.
	Title string

	// Version is info.version. Defaults to "1.0.0". Bump this when
	// your wire contract changes — Spectral diff in CI compares
	// successive versions of the same spec.
	Version string

	// Description is info.description. Markdown is permitted (the
	// OpenAPI spec allows CommonMark there).
	Description string

	// Contact is info.contact. Optional; empty means "omitted from
	// spec". Most clients ignore this; Stoplight + Postman surface
	// it on the docs page.
	Contact *Contact

	// License is info.license. Optional; same notes as Contact.
	License *License

	// Servers is the list of base URLs the spec advertises under
	// servers[]. When empty, the plugin synthesizes a single entry
	// from the request host at serve time so a local dev hit to
	// /__nexus/openapi/spec.json still sees "http://localhost:8080"
	// without configuration.
	Servers []Server

	// PublicRoot, when nil or *true, also mounts /openapi.json and
	// /api-docs at the API root in addition to the namespaced
	// /__nexus/openapi/ paths. Disable only if your gateway already
	// hosts these paths and you want the framework to stay out of
	// their way.
	PublicRoot *bool

	// ExcludeAdmin, when nil or *true, omits framework-owned
	// /__nexus/* paths from the spec. Customers shouldn't see admin
	// routes in the SDK they generate. Flip to *false for an
	// admin-facing variant.
	ExcludeAdmin *bool

	// IncludeGraphQL, when *true, also emits a /graphql operation
	// for GraphQL endpoints. Defaults to false because OpenAPI
	// describes REST poorly when the underlying transport is
	// GraphQL — most teams expose the GraphQL schema separately
	// via /graphql?schema or graphql-introspection. The flag is
	// here for the rare case where a customer must consume both
	// transports through one spec.
	IncludeGraphQL *bool

	// SwaggerUIVersion pins the CDN version of swagger-ui-dist
	// loaded by the /ui page. Default "5.20.1". Override only when
	// pinning to an audited release.
	SwaggerUIVersion string
}

Config controls the metadata block of the generated spec and a handful of behavior toggles. Everything else (paths, operations, schemas) is derived from the live registry.

type Contact

type Contact struct {
	Name  string `json:"name,omitempty"`
	URL   string `json:"url,omitempty"`
	Email string `json:"email,omitempty"`
}

Contact / License / Server mirror their OpenAPI counterparts. Repeated here so callers can configure them in Go without dragging in an OpenAPI library as a public dep.

type Document

type Document struct {
	OpenAPI    string                `json:"openapi"`
	Info       Info                  `json:"info"`
	Servers    []Server              `json:"servers,omitempty"`
	Paths      map[string]PathItem   `json:"paths"`
	Components *Components           `json:"components,omitempty"`
	Tags       []Tag                 `json:"tags,omitempty"`
	Security   []SecurityRequirement `json:"security,omitempty"`
}

Document is the root OpenAPI 3.1 object. The order of fields follows the spec's document outline so the serialized output is readable end-to-end.

type Info

type Info struct {
	Title          string   `json:"title"`
	Version        string   `json:"version"`
	Description    string   `json:"description,omitempty"`
	TermsOfService string   `json:"termsOfService,omitempty"`
	Contact        *Contact `json:"contact,omitempty"`
	License        *License `json:"license,omitempty"`
}

Info populates the spec's info block. Required: Title, Version.

type License

type License struct {
	Name string `json:"name"`
	URL  string `json:"url,omitempty"`
}

type MediaType

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

MediaType carries the schema for one MIME type within a request body or response. The framework writes application/json only; other media types stay open for plugins that wrap multipart, NDJSON, or CSV transports.

type Operation

type Operation struct {
	Tags        []string              `json:"tags,omitempty"`
	Summary     string                `json:"summary,omitempty"`
	Description string                `json:"description,omitempty"`
	OperationID string                `json:"operationId,omitempty"`
	Parameters  []Parameter           `json:"parameters,omitempty"`
	RequestBody *RequestBody          `json:"requestBody,omitempty"`
	Responses   map[string]Response   `json:"responses"`
	Security    []SecurityRequirement `json:"security,omitempty"`
	Deprecated  bool                  `json:"deprecated,omitempty"`
}

Operation describes one method on a path.

type Parameter

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

Parameter is a path/query/header/cookie parameter. The framework populates these from path placeholders (":id" → in=path) and from known query-style Args struct fields.

type PathItem

type PathItem struct {
	Summary     string      `json:"summary,omitempty"`
	Description string      `json:"description,omitempty"`
	Get         *Operation  `json:"get,omitempty"`
	Put         *Operation  `json:"put,omitempty"`
	Post        *Operation  `json:"post,omitempty"`
	Delete      *Operation  `json:"delete,omitempty"`
	Patch       *Operation  `json:"patch,omitempty"`
	Head        *Operation  `json:"head,omitempty"`
	Options     *Operation  `json:"options,omitempty"`
	Parameters  []Parameter `json:"parameters,omitempty"`
}

PathItem holds the per-method operations for a single URL pattern. OpenAPI calls these "Path Item Objects".

type RequestBody

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

RequestBody describes a request payload. For nexus the framework always uses application/json; we may add multipart later for file uploads.

type Response

type Response struct {
	Description string               `json:"description"`
	Content     map[string]MediaType `json:"content,omitempty"`
}

Response is one entry in the responses map of an Operation. The framework's typed return type populates Content["application/json"].

type Schema

type Schema struct {
	Ref                  string             `json:"$ref,omitempty"`
	Type                 string             `json:"type,omitempty"`   // "string" | "integer" | "number" | "boolean" | "array" | "object"
	Format               string             `json:"format,omitempty"` // "date-time" | "byte" | ...
	Description          string             `json:"description,omitempty"`
	Items                *Schema            `json:"items,omitempty"`      // when Type == "array"
	Properties           map[string]*Schema `json:"properties,omitempty"` // when Type == "object"
	Required             []string           `json:"required,omitempty"`   // when Type == "object"
	Enum                 []any              `json:"enum,omitempty"`
	Nullable             bool               `json:"nullable,omitempty"`             // OpenAPI 3.1 prefers `type: ["string", "null"]` — kept for tooling compat
	AdditionalProperties *Schema            `json:"additionalProperties,omitempty"` // when Type == "object" (map)
	Example              any                `json:"example,omitempty"`
	Deprecated           bool               `json:"deprecated,omitempty"`
}

Schema is the JSON-Schema-derived subset OpenAPI 3.1 uses for describing types. The framework converts each registry.TypeRef to a Schema; named refs land in Components.Schemas and Schema.Ref points at them.

type SecurityRequirement

type SecurityRequirement map[string][]string

SecurityRequirement is the per-operation "this op requires X" map. Each key is a SecurityScheme name; the slice value is a list of scopes (always empty for non-OAuth2 schemes, but the spec demands the array shape).

type SecurityScheme

type SecurityScheme struct {
	Type         string `json:"type"`                   // "http" | "apiKey" | "oauth2" | "openIdConnect"
	Scheme       string `json:"scheme,omitempty"`       // "bearer" for type=http
	BearerFormat string `json:"bearerFormat,omitempty"` // "JWT" hint when applicable
	In           string `json:"in,omitempty"`           // "header" | "query" | "cookie" — for type=apiKey
	Name         string `json:"name,omitempty"`         // header/cookie/query param name — for type=apiKey
	Description  string `json:"description,omitempty"`
}

SecurityScheme describes one auth mechanism. nexus generates a "bearer" entry when auth.Bearer is in use, "apiKey" for API key extractors, "cookie" for cookie-based auth.

type Server

type Server struct {
	URL         string `json:"url"`
	Description string `json:"description,omitempty"`
}

type Tag

type Tag struct {
	Name        string `json:"name"`
	Description string `json:"description,omitempty"`
}

Tag groups operations on the Swagger UI sidebar. The framework generates one tag per nexus.Module so the docs are organized the same way the dashboard's architecture canvas is.

Jump to

Keyboard shortcuts

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