freshcrate
Skin:/
Home > Frameworks > go-apispec

go-apispec

Generate OpenAPI 3.1 specs from Go source code via static analysis — zero annotations, automatic framework detection

Why this rank:Strong adoptionRecent releaseHealthy release cadence

Description

Generate OpenAPI 3.1 specs from Go source code via static analysis — zero annotations, automatic framework detection

README

go-apispec: Generate OpenAPI from Go code

CI Release Coverage Go VersionLicense Go Reference

go-apispec analyzes your Go source code and generates an OpenAPI 3.1 spec (YAML or JSON). Point it at your module — it detects the framework, follows the call graph from routes to handlers, and infers request/response types from real code.

Quick Start

# Install
go install github.com/antst/go-apispec/cmd/apispec@latest

# Generate (auto-detects framework)
apispec --dir ./your-project --output openapi.yaml

That's it. The tool detects your framework, finds all routes, resolves handler types, and writes the spec.

Features

Framework Support

Framework Routes Params Request Body Responses Mounting/Groups
Chi Full chi.URLParam, render pkg json.Decode, render.DecodeJSON json.Encode, render.JSON, w.Write Mount, Group
Gin Full c.Param, c.Query ShouldBindJSON, BindJSON c.JSON, c.String, c.Data Group
Echo Full c.Param, c.QueryParam c.Bind c.JSON, c.String, c.Blob Group
Fiber Full c.Params, c.Query c.BodyParser c.JSON, c.Status().JSON Mount, Group
Gorilla Mux Full Path template {id} json.Decode json.Encode, w.Write PathPrefix, Subrouter
net/http Basic Path template json.Decode json.Encode, w.Write, http.Error Nested ServeMux

Projects using multiple frameworks simultaneously are fully supported — all routes from all detected frameworks appear in the spec.

All frameworks also detect fmt.Fprintf, io.Copy, and io.WriteString as response writes.

Analysis Capabilities

Response Detection

  • Content-Type inference from w.Header().Set("Content-Type", "image/png")
  • Dynamic content-type fallback: w.Header().Set("Content-Type", doc.MimeType)application/octet-stream (variable MIME types don't leak Go field paths into the spec)
  • WriteHeader(201) + json.Encode(user) merged into a single 201 response with schema
  • Error helper functions: writeJSONError(w, http.StatusBadRequest, "msg") → 400 response with ErrorResponse schema, traced through function parameters via ParamArgMap
  • Multiple calls to same helper: writeJSONError(w, 400, ...) + writeJSONError(w, 404, ...) → both status codes captured with correct schemas
  • Status code variable resolution: status := http.StatusCreated; w.WriteHeader(status) → 201
  • Cross-function status codes: w.WriteHeader(getStatus()) where getStatus() returns a constant
  • Multiple response types for the same status code → oneOf schema
  • []byte responses → type: string, format: binary
  • Bodyless status codes (1xx, 204, 304) never get body schemas (per RFC 7231)
  • Implicit 200 for handlers that write a body without explicit WriteHeader

Type Resolution

  • Generic struct instantiation: APIResponse[User] → schema with Data: $ref User
  • Interface resolution: handlers registered via interface → concrete implementation schemas
  • interface{} parameter resolution: respondJSON(w, 201, user) where data is interface{} → resolves to concrete User type from the caller's argument
  • Conditional HTTP methods via CFG: switch r.Method { case "GET": ... case "POST": ... } → separate operations
  • Route path variables: path := "/users"; r.GET(path, h) → resolves variable to literal path
  • Decode receiver tracing: json.NewDecoder(file).Decode(&cfg) not misclassified as request body
  • io.Copy source tracing: io.Copy(w, strings.NewReader(...))type: string; io.Copy(w, file)format: binary

Documentation Extraction

  • Go doc comments on handler functions → OpenAPI summary and description
  • First sentence → summary, full comment → description (single-sentence comments don't duplicate)
  • No annotations needed — existing Go doc comments just work
  • Config overrides take precedence over doc comments

Schema Inference

  • Required fields from json:",omitempty" absence and binding:"required" tags
  • Validator dive tag: validate:"dive,email" on []string → items schema has format: email
  • Mux.Vars() map index expressions → path parameter names
  • Type mappings for time.Time, uuid.UUID, and custom types

Output Quality

  • Deterministic YAML/JSON — sorted map keys, identical output across runs, safe for CI diffing
  • Short names by default — DocumentHandler.GetContent instead of github.com/org/.../http.Deps.DocumentHandler.GetContent
  • Config merging — --config extends auto-detected framework defaults instead of replacing them

Call Graph Visualization

Interactive Cytoscape.js diagrams with:

  • Hierarchical tree layout with zoom, pan, and click-to-highlight
  • CFG branch coloring: green (if-then), red dashed (if-else), purple (switch-case)
  • Branch labels showing case values (e.g., "GET", "POST")
  • Paginated mode for large graphs (1000+ edges)
  • PNG/SVG export
apispec --dir ./my-project --output openapi.yaml --diagram diagram.html

Usage

# Basic generation
apispec --dir ./my-project --output openapi.yaml

# With custom config
apispec --dir ./my-project --config apispec.yaml --output openapi.yaml

# Legacy naming (fully-qualified operationIds and schema names)
apispec --dir ./my-project --output openapi.yaml --short-names=false

# With call graph diagram
apispec --dir ./my-project --output openapi.yaml --diagram diagram.html

# Skip CGO packages
apispec --dir ./my-project --output openapi.yaml --skip-cgo

# Tune limits for large codebases
apispec --dir ./my-project --output openapi.yaml --max-nodes 100000 --max-recursion-depth 15

# Performance profiling
apispec --dir ./my-project --output openapi.yaml --cpu-profile --mem-profile

Key Flags

Flag Short Default Description
--output -o openapi.json Output file (.yaml/.json)
--dir -d . Project directory
--config -c Custom YAML config
--short-names true Strip module paths from names
--diagram -g Save call graph as HTML
--title -t Generated API API title
--api-version -v 1.0.0 API version
--skip-cgo true Skip CGO packages
--max-nodes -mn 50000 Max call graph nodes
--max-recursion-depth -mrd 10 Max recursion depth
--verbose -vb false Verbose output

Full flag list: apispec --help

Programmatic Usage

import (
    "os"
    "github.com/antst/go-apispec/generator"
    "github.com/antst/go-apispec/spec"
    "gopkg.in/yaml.v3"
)

func main() {
    cfg := spec.DefaultChiConfig() // or DefaultGinConfig, DefaultEchoConfig, etc.
    gen := generator.NewGenerator(cfg)
    openapi, err := gen.GenerateFromDirectory("./your-project")
    if err != nil { panic(err) }
    data, _ := yaml.Marshal(openapi)
    os.WriteFile("openapi.yaml", data, 0644)
}

Configuration

Auto-detection works for most projects. For custom behavior, create apispec.yaml:

info:
  title: My API
  version: 2.0.0

shortNames: true  # false for legacy fully-qualified names

framework:
  routePatterns:
    - callRegex: ^(?i)(GET|POST|PUT|DELETE|PATCH)$
      recvTypeRegex: ^github\.com/gin-gonic/gin\.\*(Engine|RouterGroup)$
      handlerArgIndex: 1
      methodFromCall: true
      pathFromArg: true
      handlerFromArg: true

typeMapping:
  - goType: time.Time
    openapiType: { type: string, format: date-time }
  - goType: uuid.UUID
    openapiType: { type: string, format: uuid }

externalTypes:
  - name: github.com/gin-gonic/gin.H
    openapiType: { type: object, additionalProperties: true }

Full configuration examples for each framework: see the Default*Config() functions in internal/spec/config.go for the built-in patterns.

How It Works

Go source → Package loading & type-checking → Framework detection
  → AST traversal → Call graph + CFG construction → Pattern matching
  → OpenAPI mapping → YAML/JSON output
  1. Loads and type-checks all Go packages in the module
  2. Detects web frameworks from imports (supports multiple frameworks simultaneously)
  3. Builds a call graph from router registrations to handlers
  4. Builds a control-flow graph (CFG) via golang.org/x/tools/go/cfg for branch analysis
  5. Matches route, request, response, and parameter patterns against the call graph
  6. Resolves conditional methods, generic types, and interface implementations using CFG and type analysis
  7. Maps Go types to OpenAPI schemas (structs, enums, aliases, generics, validators)
  8. Serializes with sorted keys for deterministic output

Known Limitations

These are inherent to static analysis — analyzing code without executing it:

Limitation Example What Happens
Reflection-based routing Routes registered via reflect.Value.Call Not visible in static analysis
Computed paths r.GET("/api/" + version, handler) String concatenation not evaluated; only literal and variable-assigned paths resolved
Complex cross-function values func compute() int { return a + b }; WriteHeader(compute()) Only functions with a single constant return are resolved; computed values are not traced

Interactive Diagram Server

# Build and start
go build -o apidiag ./cmd/apidiag
./apidiag --dir ./my-project --port 8080
# Open http://localhost:8080

Provides a web UI for exploring call graphs with filtering, pagination, and export. See cmd/apidiag/README.md.

Development

# Build
make build

# Test
make test

# Lint
make lint

# Coverage
make coverage

# Update golden files after intentional output changes
# (generates to temp, shows diff, requires confirmation)
go test ./internal/engine/ -run TestUpdateGolden -v

Project Structure

go-apispec/
├── cmd/apispec/          CLI entry point
├── cmd/apidiag/          Interactive diagram server
├── generator/            High-level generator API
├── spec/                 Public types (re-exports from internal/spec)
├── internal/
│   ├── core/             Framework detection
│   ├── engine/           Generation engine
│   ├── metadata/         AST analysis and metadata extraction
│   └── spec/             OpenAPI mapping, patterns, schemas
├── pkg/patterns/         Gitignore-style pattern matching
└── testdata/             Framework fixtures + golden files

Golden File Tests

Every testdata/ directory has expected_openapi.json (short names) and expected_openapi_legacy.json (fully-qualified). Golden files use relative paths only — no machine-specific absolute paths.

One code path: generateGoldenSpec() is the single function used by both comparison and generation. Tests never overwrite golden files.

# Compare (runs in CI — fails on mismatch):
go test ./internal/engine/ -run TestGolden -v

# Update after intentional changes (explicit, never automatic):
go test ./internal/engine/ -run TestUpdateGolden -v

Contributing

See CONTRIBUTING.md. In short:

  1. Fork, branch, make changes
  2. Add tests (make test)
  3. Run lint (make lint)
  4. Open a PR

License

Apache License 2.0 — see LICENSE.

Originally forked from apispec by Ehab Terra.

Release History

VersionChangesUrgencyDate
v0.4.14## What's Changed * test: meaningful unit tests to bump coverage above 95% by @antst in https://github.com/antst/go-apispec/pull/28 * fix: filter helper-internal error-fallback writes from caller schemas (#27) by @antst in https://github.com/antst/go-apispec/pull/29 **Full Changelog**: https://github.com/antst/go-apispec/compare/v0.4.13...v0.4.14High5/20/2026
v0.4.9## What's Changed * feat: JSON DTO format inference + requestBody.required by @antst in https://github.com/antst/go-apispec/pull/17 **Full Changelog**: https://github.com/antst/go-apispec/compare/v0.4.8...v0.4.9High4/28/2026
v0.4.7## What's Changed * feat: extract Go doc comments as OpenAPI summary/description by @antst in https://github.com/antst/go-apispec/pull/14 **Full Changelog**: https://github.com/antst/go-apispec/compare/v0.4.6...v0.4.7High4/14/2026
v0.4.6## What's Changed * fix: isLikelyMediaType rejects Go module paths with multiple slashes by @antst in https://github.com/antst/go-apispec/pull/11 **Full Changelog**: https://github.com/antst/go-apispec/compare/v0.4.5...v0.4.6High4/8/2026
v0.4.5## What's Changed * fix: dynamic content-type falls back to application/octet-stream by @antst in https://github.com/antst/go-apispec/pull/10 **Full Changelog**: https://github.com/antst/go-apispec/compare/v0.4.4...v0.4.5Medium4/8/2026
v0.4.4## What's Changed * feat: detect error responses through helper functions via ParamArgMap by @antst in https://github.com/antst/go-apispec/pull/9 **Full Changelog**: https://github.com/antst/go-apispec/compare/v0.4.3...v0.4.4Medium4/8/2026
v0.4.3## What's Changed * test: comprehensive coverage push — 86% to 96% by @antst in https://github.com/antst/go-apispec/pull/8 **Full Changelog**: https://github.com/antst/go-apispec/compare/v0.4.2...v0.4.3Medium4/6/2026
v0.4.2## What's Changed * ci: update action versions and use official golangci-lint action by @antst in https://github.com/antst/go-apispec/pull/6 * feat: nested ServeMux support for net/http by @antst in https://github.com/antst/go-apispec/pull/7 **Full Changelog**: https://github.com/antst/go-apispec/compare/v0.4.1...v0.4.2Medium4/5/2026
v0.4.1## What's Changed * fix: add CI/Release badges, fix test that mutated fixture file by @antst in https://github.com/antst/go-apispec/pull/2 * feat: multi-framework detection and pattern merging by @antst in https://github.com/antst/go-apispec/pull/1 * test: comprehensive coverage improvement — 67% to 85% by @antst in https://github.com/antst/go-apispec/pull/3 * fix: detector tests use []string after multi-framework merge by @antst in https://github.com/antst/go-apispec/pull/4 * docs: rewrite READMedium4/3/2026
v0.4.0**Full Changelog**: https://github.com/antst/go-apispec/commits/v0.4.0 **Full Changelog**: https://github.com/antst/go-apispec/commits/v0.4.0Medium4/3/2026

Dependencies & License Audit

Loading dependencies...

Similar Packages

goaDesign-first Go framework that generates API code, documentation, and clients. Define once in an elegant DSL, deploy as HTTP and gRPC services with zero drift between code and docs.v3.28.0
suricataType-safe AI agents for Go. Suricata combines LLM intelligence with Go’s strong typing, declarative YAML specs, and code generation to build safe, maintainable, and production-ready AI agents.0.0.0
go-orcaSelf-hosted AI workflow orchestration server. Runs multi-phase LLM pipelines (Director → Architect → Implementer → QA) and delivers structured artifacts via PR, webhook, or bundle.sha-1eba134
muxdAn open-source AI coding agent that lives in your terminal. Multi-provider, multi-channel, persistent sessions with git-like branching.v0.71.0
gorm-queryA strongly-typed query builder and generic repository libraryv1.4.5

More in Frameworks

spec_driven_developSpec-Driven Develop is a platform-agnostic AI agent skill that automates the pre-development workflow for large-scale complex tasks. It is not a framework, not a runtime, not a package manager — it is
deer-flowAn open-source long-horizon SuperAgent harness that researches, codes, and creates. With the help of sandboxes, memories, tools, skill, subagents and message gateway, it handles different levels of ta
tqdmFast, Extensible Progress Meter
simBuild, deploy, and orchestrate AI agents. Sim is the central intelligence layer for your AI workforce.