OpenAPI 3.1, generated from your real Go code.
Point apispec at your module and get an accurate spec — routes, parameters, request and response bodies — inferred by walking the call graph. No annotations. No drift.
Free & open source · one command · works with the router you already use.
Detects the router you already use
Specs that match the code — because they come from the code.
Hand-written annotations rot the moment someone forgets to update them. apispec reads what your program actually does.
Generated from real code
Routes, parameters, request bodies and responses are inferred by analyzing the AST and walking the call graph to the actual handlers — never from comments that drift out of sync.
Framework-aware out of the box
First-class detection for Gin, Echo, Chi, Fiber, Gorilla Mux and net/http — it follows each router’s conventions to find the real route table.
Type-aware
Resolves aliases and enums to primitives, maps validator tags to OpenAPI constraints, and handles generics, arrays, pointers and external types.
Extensible by config
Framework behaviour is described as regex patterns in YAML — add or tweak a framework without touching core logic.
Visualize the call graph
Optional interactive HTML diagram of how requests flow to handlers — plus a standalone paginated server for very large codebases.
Your handler in. A faithful spec out.
Notice the validator tags becoming real OpenAPI constraints — required, format: email, minimum/maximum — with nothing hand-written.
// your handler — plain Gin, no annotations, no magic comments
r.POST("/users", createUser)
type CreateUserReq struct {
Email string `json:"email" binding:"required,email"`
Age int `json:"age" binding:"gte=0,lte=130"`
}
func createUser(c *gin.Context) {
var req CreateUserReq
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
c.JSON(201, User{ID: 1, Email: req.Email})
} # apispec --output openapi.yaml
paths:
/users:
post:
requestBody:
content:
application/json:
schema: { $ref: '#/components/schemas/CreateUserReq' }
responses:
'201':
content:
application/json:
schema: { $ref: '#/components/schemas/User' }
components:
schemas:
CreateUserReq:
type: object
required: [email] # from binding:"required"
properties:
email: { type: string, format: email }
age: { type: integer, minimum: 0, maximum: 130 } From CLI to browser to call-graph.
The same analysis engine, packaged for however you like to work.
Auto-detects the framework, loads a default config you can override, and writes an OpenAPI 3.1 spec as YAML or JSON. The workhorse.
$ apispec --output openapi.yaml Configure apispec, preview the generated spec live, and explore the call graph at /diagram — all in your browser.
$ apispecui A standalone, headless interactive call-graph server — the same engine, for digging into how large codebases actually wire up.
$ apidiag Four steps, zero annotations.
Point at your module
Run apispec from inside any Go module. No tags, no setup, no special build.
Detect the framework
It recognises your router and locates the real route table from the code.
Walk & infer
It follows the call graph to each handler and infers request and response types from real code.
Write the spec
Out comes a valid OpenAPI 3.1 document — plus an optional interactive diagram.
Install → generate → explore.
A real end-to-end run on a Go service. Watch the full walkthrough →
Generate your first spec in under a minute.
Requires Go 1.26+. Other install methods (Homebrew-style scripts, build from source) are in the docs.
go install github.com/ehabterra/apispec/cmd/apispec@latest apispec --output openapi.yaml Stop hand-writing OpenAPI.
Let your code describe itself. One command, an accurate 3.1 spec, and a call graph you can actually read.