| name | go-swagger |
| description | Use when adding or maintaining OpenAPI/Swagger documentation for a Go HTTP API. Covers swaggo/swag annotation comments (@Summary, @Param, @Success, @Router, @Security), the swag CLI workflow, framework integration for Gin/Echo/Fiber/Chi/net-http, security definitions (Bearer/JWT, OAuth2, API key), and struct tags (example, enums, swaggertype, swaggerignore). Apply when a project imports github.com/swaggo/swag or any of the swaggo UI adapters, or when you need to expose /swagger/index.html. |
| user-invocable | false |
| license | MIT |
| compatibility | Designed for Claude Code or similar AI coding agents. Requires Go 1.21+, swaggo/swag v1.16+ (CLI: `swag`). |
| metadata | {"author":"muratmirgun","version":"0.1.0","openclaw":{"emoji":"📋","homepage":"https://github.com/muratmirgun/gophers","requires":{"bins":["go"]},"install":[{"kind":"go","package":"github.com/swaggo/swag/cmd/swag@latest","bins":["swag"]}]}} |
| allowed-tools | Read Edit Write Glob Grep Bash(go:*) Bash(golangci-lint:*) |
Go Swagger / OpenAPI with swaggo
github.com/swaggo/swag is the de-facto annotation-driven OpenAPI generator for Go. You annotate handlers with // @... comments, run the swag CLI, and get docs/swagger.json, docs/swagger.yaml, and docs/docs.go for the UI.
Core Rules
- Docs are a contract. A field documented as required is the API's promise; a mismatch with the implementation is a bug.
- Annotations live next to handlers. Not in a separate
docs/ folder — comments rot when separated from code.
- Regenerate on every change.
swag init is part of the build (go generate or a Makefile target). Stale docs/ is worse than no docs.
- The
docs package must be imported. A blank import (_ "yourmod/docs") registers the spec at process start.
- Use named structs for request/response bodies. swag cannot derive a schema from
map[string]any or a primitive type.
- Security definitions match implementation. If the API enforces JWT, declare
@securityDefinitions.apikey Bearer and annotate every protected endpoint with @Security Bearer.
Install and Bootstrap
go install github.com/swaggo/swag/cmd/swag@latest
swag init
swag init -g cmd/api/main.go
swag fmt
Wire the UI for your framework — choose one:
import (
swaggerFiles "github.com/swaggo/files"
ginSwagger "github.com/swaggo/gin-swagger"
)
r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
r.GET("/swagger/*", echoSwagger.WrapHandler)
app.Get("/swagger/*", fiberSwagger.WrapHandler(swaggerFiles.Handler))
mux.Handle("/swagger/", httpSwagger.Handler(swaggerFiles.Handler))
Import the generated spec:
import _ "github.com/acme/myapi/docs"
import docs "github.com/acme/myapi/docs"
Read references/swag-cli.md for the CLI flag inventory and Makefile patterns.
General API Info
Place in the file passed via -g (usually main.go):
For multi-environment deployments, set host/basepath at runtime instead of hard-coding:
import docs "github.com/acme/myapi/docs"
func main() {
docs.SwaggerInfo.Host = os.Getenv("API_HOST")
docs.SwaggerInfo.BasePath = "/api/v1"
}
Operation Annotations
func GetOrder(c *gin.Context) { }
@Param: @Param <name> <in> <type> <required> "<desc>" [attributes] — <in> is one of path, query, body, header, formData. Useful attributes: default(v), minimum(n), maximum(n), Enums(a,b,c), example(v), collectionFormat(multi).
@Success / @Failure: @<kw> <code> {<kind>} <type> "<desc>" — {object} (struct), {array} (slice), or a primitive (string, integer). Generics (swag v2): api.Response[model.Order]. Composition: api.Response{data=model.Order}.
Read references/annotations.md for the full annotation grammar, edge cases, and security definitions.
Security
Declare schemes once globally (@securityDefinitions.apikey Bearer, @securityDefinitions.oauth2.authorizationCode, @securityDefinitions.basic) and apply per endpoint:
Endpoints without @Security are documented as public — match the implementation.
Struct Tags
Enrich models without changing their Go type. Common tags: example, enums:"a,b,c", minimum/maximum, minLength/maxLength, format, swaggertype (override detected type, e.g. time.Time → string), swaggerignore:"true", and extensions:"x-nullable,x-deprecated=true".
type CreateOrderRequest struct {
Status string `json:"status" enums:"pending,paid,shipped"`
Total int64 `json:"total" minimum:"0" example:"19999"`
PlacedAt time.Time `json:"placed_at" swaggertype:"string" format:"date-time"`
Internal string `json:"-" swaggerignore:"true"`
}
Read references/struct-tags.md for type overrides (time.Time, uuid.UUID, decimal.Decimal, custom scalars) and NULL handling.
Make Target
.PHONY: docs
docs:
swag fmt
swag init -g cmd/api/main.go --parseDependency --parseInternal
check-docs: docs
@git diff --quiet docs || (echo "docs/ is stale; run make docs"; exit 1)
Run make check-docs in CI to catch annotation drift before merge.
Anti-Patterns
| Anti-pattern | Why it hurts | Do this instead |
|---|
Forgetting _ "yourmod/docs" | UI loads empty, no errors | Add the blank import in main |
@Param body string | swag cannot derive a schema from a primitive | Use a named struct |
Stale docs/ after handler change | Docs lie to clients | Regenerate in CI; fail on drift |
| General info in wrong file | Spec has no title/host | Use -g <file> or move to main |
{object} map[string]any | swag silently empty | Define a wrapper struct |
No @Security on protected route | UI shows no lock icon | Add @Security everywhere auth is required |
Multi-word @Tags unquoted | Tags split on whitespace | Quote: @Tags "order management" |
Exposing /swagger/* in production unconditionally | Public API surface map | Gate behind env flag or auth |
Verification Checklist
References