openapi

package
v1.5.0 Latest Latest
Warning

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

Go to latest
Published: Mar 30, 2026 License: MIT Imports: 20 Imported by: 0

Documentation

Overview

Package openapi provides automatic OpenAPI 3.0 specification generation for Aegis.

This plugin generates interactive API documentation with:

  • OpenAPI 3.0.3 specification (JSON)
  • Scalar documentation UI (interactive browser interface)
  • Automatic schema generation from Go structs
  • Security scheme definitions (cookie, bearer)
  • Global pending queue for decoupled route registration

Documentation Features:

  • Auto-generates schemas from Go types using reflection
  • Parses validation tags for schema constraints
  • Supports request/response body documentation
  • Security requirements (protected vs public routes)
  • Tag-based organization
  • Automatic operationId derivation from Method+Path
  • Forces required: true on all path parameters

Usage:

Any plugin or user code calls openapi.Doc() to register a route:

openapi.Doc(openapi.Route{
    Method:  "GET",
    Path:    "/api/users/{id}",
    Summary: "Get user by ID",
    Tags:    []string{"Users"},
    Auth:    true,
    Params: []openapi.Param{
        {Name: "id", In: "path", Type: "string", Required: true},
    },
    Responses: openapi.Responses{
        200: openapi.ResponseOf[UserResponse]("User retrieved"),
    },
})

The OpenAPI plugin is always registered last in a.Use():

a.Use(ctx, openapi.New(&openapi.Config{
    Title:      "My App API",
    Version:    "1.0.0",
    EnableDocs: true,
    DocsPath:   "/docs",
    SpecPath:   "/openapi.json",
}))

Package openapi provides OpenAPI 3.0 specification types and generation.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Doc added in v1.5.0

func Doc(r Route)

Doc registers a route for OpenAPI documentation.

This is the single public function for documenting API routes. It is safe to call at any point — during init(), inside MountRoutes, or anywhere in application startup — regardless of whether the OpenAPI plugin has been registered yet.

If the OpenAPI plugin is already loaded, the route is registered immediately. Otherwise it is buffered until the plugin initializes.

Example:

openapi.Doc(openapi.Route{
    Method:  "POST",
    Path:    "/api/users/{id}/invite",
    Summary: "Invite a user",
    Tags:    []string{"Users"},
    Auth:    true,
    Params: []openapi.Param{
        {Name: "id", In: "path", Type: "string", Required: true},
    },
    Body:   openapi.BodyOf[InviteRequest](),
    Responses: openapi.Responses{
        200: openapi.ResponseOf[InviteResponse]("Invitation sent"),
        404: openapi.Text("User not found"),
    },
})

Types

type BodySchema added in v1.5.0

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

BodySchema holds a generated request body schema. Use BodyOf[T]() or RefBody() to construct one.

func BodyOf added in v1.5.0

func BodyOf[T any]() *BodySchema

BodyOf generates a request body schema from a Go struct type via reflection. The schema is registered in components/schemas under the struct's type name, enabling $ref reuse across endpoints.

Example:

Body: openapi.BodyOf[CreateUserRequest]()

func RefBody added in v1.5.0

func RefBody(schemaName string) *BodySchema

RefBody creates a request body that references an existing named schema. The caller is responsible for registering the referenced schema elsewhere (e.g. via addCommonSchemas).

Example:

Body: openapi.RefBody("LoginRequest")

type Components

type Components struct {
	Schemas         map[string]*Schema         `json:"schemas,omitempty"`
	Responses       map[string]*Response       `json:"responses,omitempty"`
	Parameters      map[string]*Parameter      `json:"parameters,omitempty"`
	RequestBodies   map[string]*RequestBody    `json:"requestBodies,omitempty"`
	Headers         map[string]*Header         `json:"headers,omitempty"`
	SecuritySchemes map[string]*SecurityScheme `json:"securitySchemes,omitempty"`
}

Components holds reusable objects for different aspects of the OAS.

type Config

type Config struct {
	// Title for the API documentation
	Title string
	// Version of the API
	Version string
	// Description of the API
	Description string
	// Servers to include in the spec (for multi-environment APIs)
	Servers []Server
	// Contact information for API maintainers
	Contact *Contact
	// License information for the API
	License *License
	// EnableDocs enables the Scalar documentation UI
	EnableDocs bool
	// DocsPath is the path for the documentation UI (e.g., "/docs").
	// The plugin no longer inserts its own name into the path.
	// If empty, defaults to "/docs".
	DocsPath string
	// SpecPath is the path for the OpenAPI spec JSON (e.g., "/openapi.json").
	// If empty, defaults to "/openapi.json".
	SpecPath string
}

Config holds OpenAPI plugin configuration.

Example:

cfg := &openapi.Config{
    Title:      "My App API",
    Version:    "1.0.0",
    Description: "Authentication and application API",
    EnableDocs: true,
    DocsPath:   "/docs",
    SpecPath:   "/openapi.json",
    Servers: []openapi.Server{
        {URL: "https://api.example.com", Description: "Production"},
    },
}

func DefaultConfig

func DefaultConfig() *Config

DefaultConfig returns default OpenAPI configuration.

Default Settings:

  • Title: "Aegis Authentication API"
  • Version: "1.0.0"
  • EnableDocs: true
  • Server: http://localhost:8080 (development)
  • License: MIT
  • DocsPath: "/docs"
  • SpecPath: "/openapi.json"

Returns:

  • *Config: Default configuration ready for customization

type Contact

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

Contact information for the API.

type Handler

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

Handler handles HTTP requests for OpenAPI documentation.

This handler serves:

  • OpenAPI specification in JSON format
  • Scalar interactive documentation UI

func NewHandler

func NewHandler(plugin *Plugin) *Handler

NewHandler creates a new OpenAPI handler.

Parameters:

  • plugin: Initialized OpenAPI plugin

Returns:

  • *Handler: Handler ready for route registration

func (*Handler) ServeScalarUI

func (h *Handler) ServeScalarUI(w http.ResponseWriter, req *http.Request)

ServeScalarUI serves the Scalar documentation UI.

Scalar Features:

  • Interactive API explorer
  • Request/response examples
  • Try-it-out functionality
  • Authentication testing
  • Schema visualization

Endpoint:

  • Method: GET
  • Path: Configured via Config.DocsPath (default: /docs)
  • Auth: Public

Implementation: Uses CDN-hosted Scalar UI (https://cdn.jsdelivr.net/npm/@scalar/api-reference) Loads spec from the configured spec path.

func (*Handler) ServeSpec

func (h *Handler) ServeSpec(w http.ResponseWriter, _ *http.Request)

ServeSpec serves the OpenAPI specification as JSON.

The spec is generated from all routes registered via Doc(). No metadata collection from the router is needed — the spec is fully built during plugin initialization.

Endpoint:

  • Method: GET
  • Path: Configured via Config.SpecPath (default: /openapi.json)
  • Auth: Public

Response:

  • Content-Type: application/json
  • Access-Control-Allow-Origin: * (for Swagger UI, Postman, etc.)
type Header struct {
	Description string  `json:"description,omitempty"`
	Schema      *Schema `json:"schema,omitempty"`
}

Header describes a single header parameter.

type Info

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

Info provides metadata about the API.

Example:

info := Info{
  Title:       "Aegis API",
  Version:     "1.0.0",
  Description: "Authentication API",
  Contact: &Contact{
    Name:  "API Support",
    Email: "support@example.com",
  },
}

type License

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

License information for the API.

type MediaType

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

MediaType provides schema and examples for the media type.

type OAuthFlow

type OAuthFlow struct {
	AuthorizationURL string            `json:"authorizationUrl,omitempty"`
	TokenURL         string            `json:"tokenUrl,omitempty"`
	RefreshURL       string            `json:"refreshUrl,omitempty"`
	Scopes           map[string]string `json:"scopes"`
}

OAuthFlow configuration details.

type OAuthFlows

type OAuthFlows struct {
	Implicit          *OAuthFlow `json:"implicit,omitempty"`
	Password          *OAuthFlow `json:"password,omitempty"`
	ClientCredentials *OAuthFlow `json:"clientCredentials,omitempty"`
	AuthorizationCode *OAuthFlow `json:"authorizationCode,omitempty"`
}

OAuthFlows allows configuration of the supported OAuth Flows.

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 a single API operation on a path.

This represents an HTTP method (GET, POST, etc.) on a specific path. Each operation defines:

  • Request requirements (parameters, body)
  • Response definitions (status codes, schemas)
  • Security requirements
  • Metadata (tags, summary, description)

Example:

op := &Operation{
  Tags:        []string{"Default"},
  Summary:     "Login",
  Description: "Authenticate user with email and password",
  RequestBody: &RequestBody{...},
  Responses:   map[string]*Response{...},
  Security:    []SecurityRequirement{{"cookieAuth": []string{}}},
}

type Param added in v1.5.0

type Param struct {
	Name        string
	In          string // "path", "query", "header", "cookie"
	Description string
	Required    bool   // Always forced to true when In == "path"
	Type        string // "string", "integer", "boolean", "array"
	Format      string // "uuid", "date-time", "email", etc.
	Enum        []string
}

Param describes a single operation parameter.

When In == "path", Required is forcibly set to true regardless of what the caller passes. This is a hard requirement of the OpenAPI 3.0 spec.

func PaginationQueryParams added in v1.5.0

func PaginationQueryParams() []Param

PaginationQueryParams returns the standard OpenAPI query parameters used by list endpoints that support core.ParsePagination.

Supported query params:

  • page (1-based, integer)
  • limit (items per page, integer)

type Parameter

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

Parameter describes a single operation parameter.

type PathItem

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

PathItem describes operations available on a single path.

type Plugin

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

Plugin provides automatic OpenAPI 3.0 documentation generation.

This plugin integrates with the Aegis routing system to collect route documentation registered via the global Doc() function and generate comprehensive API documentation with interactive UI.

Features:

  • Decoupled registration via global Doc() function
  • Pending queue that buffers docs until plugin initializes
  • Thread-safe spec updates
  • Scalar UI integration for interactive documentation
  • Multiple security scheme support
  • Schema validation from Go struct tags
  • Automatic operationId derivation

func New

func New(cfg *Config) *Plugin

New creates a new OpenAPI plugin with automatic schema generation.

Initialization:

  1. Create base OpenAPI 3.0.3 spec
  2. Configure servers, contact, license
  3. Add security schemes (cookie, bearer)
  4. Add common schemas (Error, Success)

Parameters:

  • cfg: Plugin configuration (uses defaults if nil)

Returns:

  • *Plugin: Configured plugin ready for initialization

Example:

plugin := openapi.New(&openapi.Config{
    Title:      "My API",
    Version:    "2.0.0",
    EnableDocs: true,
    DocsPath:   "/docs",
    SpecPath:   "/openapi.json",
})

func (*Plugin) Dependencies

func (p *Plugin) Dependencies() []plugins.Dependency

Dependencies returns plugin dependencies.

func (*Plugin) Description

func (p *Plugin) Description() string

Description returns a human-readable description.

func (*Plugin) GetMigrations

func (p *Plugin) GetMigrations() []plugins.Migration

GetMigrations returns the plugin migrations.

func (*Plugin) GetSpec

func (p *Plugin) GetSpec() *Spec

GetSpec returns a copy of the current OpenAPI spec.

func (*Plugin) Init

func (p *Plugin) Init(_ context.Context, _ plugins.Aegis) error

Init initializes the OpenAPI plugin and drains all pending route registrations from the global queue.

By the time this is called, all other plugins and user code have already called Doc() to register their routes.

func (*Plugin) MountRoutes

func (p *Plugin) MountRoutes(r router.Router, prefix string)

MountRoutes registers HTTP routes for the plugin.

func (*Plugin) Name

func (p *Plugin) Name() string

Name returns the plugin identifier.

func (*Plugin) ProvidesAuthMethods

func (p *Plugin) ProvidesAuthMethods() []string

ProvidesAuthMethods returns authentication methods provided.

func (*Plugin) RegisterSchemaFromType

func (p *Plugin) RegisterSchemaFromType(name string, example any)

RegisterSchemaFromType automatically generates and registers an OpenAPI schema from a Go type. This can be used by plugins or user code to register schemas that are referenced in routes.

func (*Plugin) RequiresTables

func (p *Plugin) RequiresTables() []string

RequiresTables returns required database tables.

func (*Plugin) Version

func (p *Plugin) Version() string

Version returns the plugin version.

type RequestBody

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

RequestBody describes a single request body.

type Response

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

Response describes a single response from an API operation.

type ResponseDef added in v1.5.0

type ResponseDef struct {
	Description string
	// contains filtered or unexported fields
}

ResponseDef describes a single response entry.

func DataRefResponse added in v1.5.0

func DataRefResponse(description string, schemaName string) ResponseDef

DataRefResponse creates a response that wraps an existing named schema in the core.Response envelope: { success: bool, message: string, data: $ref }.

Example:

200: openapi.DataRefResponse("Login successful", "SessionWithUser")

func DataResponseOf added in v1.5.0

func DataResponseOf[T any](description string) ResponseDef

DataResponseOf generates a response that wraps a Go struct in the core.Response envelope: { success: bool, message: string, data: T }.

Example:

200: openapi.DataResponseOf[SessionWithUser]("Login successful")

func PaginatedResponseOf added in v1.5.0

func PaginatedResponseOf[T any](description string) ResponseDef

PaginatedResponseOf generates a plain response schema from a paginated Go struct type. Unlike DataResponseOf, this does NOT wrap the response in the core.Response envelope, because the paginated type already acts as its own envelope via fields like items, limit, offset, page, and totalCount.

Example:

200: openapi.PaginatedResponseOf[PaginatedResult[User]]("List of users")

func RefResponse added in v1.5.0

func RefResponse(description string, schemaName string) ResponseDef

RefResponse creates a response that references an existing named schema.

Example:

200: openapi.RefResponse("Success response", "Success")
401: openapi.RefResponse("Not authenticated", "Error")

func ResponseOf added in v1.5.0

func ResponseOf[T any](description string) ResponseDef

ResponseOf generates a response schema from a Go struct type via reflection. The schema is registered in components/schemas under the struct's type name, enabling $ref reuse across endpoints.

Example:

200: openapi.ResponseOf[UserResponse]("User retrieved successfully")

func TextResponse added in v1.5.0

func TextResponse(description string) ResponseDef

TextResponse is a shorthand for responses with a plain description and no body schema.

Example:

404: openapi.TextResponse("User not found")
204: openapi.TextResponse("Item deleted")

type Responses added in v1.5.0

type Responses map[int]ResponseDef

Responses maps HTTP status codes to response definitions.

type Route added in v1.5.0

type Route struct {
	// Required
	Method string // "GET", "POST", "PUT", "DELETE", "PATCH"
	Path   string // "/api/users/{id}" — use {param} style for path params

	// Optional metadata
	OperationID string
	Summary     string
	Description string
	Tags        []string
	Auth        bool // Adds BearerAuth security requirement when true
	Deprecated  bool

	// Parameters, body, and responses
	Params    []Param
	Body      *BodySchema
	Responses Responses
}

Route describes a single API endpoint for OpenAPI documentation.

This is the only struct users and plugins need to construct. Pass it to Doc() to register documentation for a route.

Example:

openapi.Doc(openapi.Route{
    Method:  "GET",
    Path:    "/api/users/{id}",
    Summary: "Get user by ID",
    Tags:    []string{"Users"},
    Auth:    true,
    Params: []openapi.Param{
        {Name: "id", In: "path", Type: "string", Required: true},
    },
    Responses: openapi.Responses{
        200: openapi.ResponseOf[UserResponse]("User retrieved"),
        404: openapi.Text("User not found"),
    },
})

type Schema

type Schema struct {
	Type                 string             `json:"type,omitempty"`
	Format               string             `json:"format,omitempty"`
	Title                string             `json:"title,omitempty"`
	Description          string             `json:"description,omitempty"`
	Properties           map[string]*Schema `json:"properties,omitempty"`
	Required             []string           `json:"required,omitempty"`
	Items                *Schema            `json:"items,omitempty"`
	Enum                 []any              `json:"enum,omitempty"`
	Example              any                `json:"example,omitempty"`
	Ref                  string             `json:"$ref,omitempty"`
	AdditionalProperties any                `json:"additionalProperties,omitempty"`

	// Validation constraints
	MinLength *int     `json:"minLength,omitempty"`
	MaxLength *int     `json:"maxLength,omitempty"`
	Pattern   string   `json:"pattern,omitempty"`
	Minimum   *float64 `json:"minimum,omitempty"`
	Maximum   *float64 `json:"maximum,omitempty"`
	MinItems  *int     `json:"minItems,omitempty"`
	MaxItems  *int     `json:"maxItems,omitempty"`
}

Schema represents a JSON Schema object.

func ArraySchema

func ArraySchema(description string, items *Schema) *Schema

ArraySchema creates an array schema.

func BooleanSchema

func BooleanSchema(description string) *Schema

BooleanSchema creates a boolean schema.

func DateTimeSchema

func DateTimeSchema(description string) *Schema

DateTimeSchema creates a date-time string schema.

func EmailSchema

func EmailSchema(description string) *Schema

EmailSchema creates an email string schema.

func GenerateSchema

func GenerateSchema(v any) *Schema

GenerateSchema creates an OpenAPI schema from a Go struct instance using reflection.

This function analyzes the struct's type information to automatically generate a JSON Schema compatible with OpenAPI 3.0.

Schema Generation:

  1. Inspect struct fields and types
  2. Parse JSON tags for field names
  3. Parse validation tags for constraints
  4. Determine required fields (non-omitempty, validation:"Required")
  5. Generate nested schemas for complex types

Supported Types:

  • Primitives: string, int, bool, float
  • Complex: struct, array, map
  • Special: time.Time (date-time format)

Validation Tags:

  • validation:"Required" -> required field
  • validation:"Length(3,50)" -> minLength/maxLength
  • validation:"Min(1),Max(100)" -> minimum/maximum
  • validation:"Match(^[a-z]+$)" -> pattern

Parameters:

  • v: Go struct instance or pointer to struct

Returns:

  • *Schema: OpenAPI schema with properties and constraints

Example:

type User struct {
  Name  string `json:"name" validation:"Required,Length(1,100)"`
  Email string `json:"email" validation:"Required,Match(^.+@.+$)"`
}
schema := GenerateSchema(User{})

func IntegerSchema

func IntegerSchema(description string) *Schema

IntegerSchema creates an integer schema.

func ObjectSchema

func ObjectSchema(description string, properties map[string]*Schema, required []string) *Schema

ObjectSchema creates an object schema.

func RefSchema

func RefSchema(ref string) *Schema

RefSchema creates a reference to a schema component.

func StringSchema

func StringSchema(description string) *Schema

StringSchema creates a string schema.

func UUIDSchema

func UUIDSchema(description string) *Schema

UUIDSchema creates a UUID string schema.

type SecurityRequirement

type SecurityRequirement map[string][]string

SecurityRequirement lists required security schemes to execute an operation.

type SecurityScheme

type SecurityScheme struct {
	Type             string      `json:"type"` // "apiKey", "http", "oauth2", "openIdConnect"
	Description      string      `json:"description,omitempty"`
	Name             string      `json:"name,omitempty"`             // For apiKey
	In               string      `json:"in,omitempty"`               // For apiKey: "query", "header", "cookie"
	Scheme           string      `json:"scheme,omitempty"`           // For http: "bearer", "basic"
	BearerFormat     string      `json:"bearerFormat,omitempty"`     // For http bearer
	Flows            *OAuthFlows `json:"flows,omitempty"`            // For oauth2
	OpenIDConnectURL string      `json:"openIdConnectUrl,omitempty"` // For openIdConnect
}

SecurityScheme defines a security scheme that can be used by operations.

type Server

type Server struct {
	URL         string                    `json:"url"`
	Description string                    `json:"description,omitempty"`
	Variables   map[string]ServerVariable `json:"variables,omitempty"`
}

Server represents a server URL.

type ServerVariable

type ServerVariable struct {
	Enum        []string `json:"enum,omitempty"`
	Default     string   `json:"Default"`
	Description string   `json:"description,omitempty"`
}

ServerVariable represents a server URL template variable.

type Spec

type Spec struct {
	OpenAPI    string                `json:"openapi"`              // OpenAPI version (3.0.3)
	Info       Info                  `json:"info"`                 // API metadata
	Servers    []Server              `json:"servers,omitempty"`    // Server URLs
	Paths      map[string]*PathItem  `json:"paths"`                // API endpoints
	Components *Components           `json:"components,omitempty"` // Reusable components
	Security   []SecurityRequirement `json:"security,omitempty"`   // Global security
	Tags       []Tag                 `json:"tags,omitempty"`       // Endpoint tags
}

Spec represents an OpenAPI 3.0 specification document.

This is the root object of an OpenAPI 3.0 document, containing all metadata, paths, components, and security definitions.

Spec Structure:

  • OpenAPI: Version ("3.0.3")
  • Info: API metadata (title, version, description)
  • Servers: API server URLs (dev, staging, production)
  • Paths: All API endpoints and operations
  • Components: Reusable schemas, security schemes
  • Security: Global security requirements
  • Tags: Endpoint categorization

func NewSpec

func NewSpec(title, version, description string) *Spec

NewSpec creates a new OpenAPI 3.0 specification with default values.

func (*Spec) AddPath

func (s *Spec) AddPath(path string, item *PathItem)

AddPath adds or updates a path in the specification.

func (*Spec) AddSchema

func (s *Spec) AddSchema(name string, schema *Schema)

AddSchema adds a reusable schema component.

func (*Spec) AddSecurityScheme

func (s *Spec) AddSecurityScheme(name string, scheme *SecurityScheme)

AddSecurityScheme adds a security scheme component.

func (*Spec) AddTag

func (s *Spec) AddTag(tag Tag)

AddTag adds a tag to the specification.

func (*Spec) ToJSON

func (s *Spec) ToJSON() ([]byte, error)

ToJSON converts the spec to JSON bytes.

type Tag

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

Tag adds metadata to a single tag.

Jump to

Keyboard shortcuts

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