Go swagger
26 production-grade Go skills for Claude Code, Gemini CLI, and opencode.
npx -y skills add muratmirgun/gophers --skill go-swaggerAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 8 stars8 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
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.
The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.
SKILL.md
8.1 KB, as published. Nobody here has run it
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 initis part of the build (go generateor a Makefile target). Staledocs/is worse than no docs. - The
docspackage 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]anyor a primitive type. - Security definitions match implementation. If the API enforces JWT, declare
@securityDefinitions.apikey Bearerand annotate every protected endpoint with@Security Bearer.
Install and Bootstrap
go install github.com/swaggo/swag/cmd/swag@latest
swag init # general info from main.go
swag init -g cmd/api/main.go # custom main path
swag fmt # format annotation comments like gofmt
Wire the UI for your framework — choose one:
// Gin
import (
swaggerFiles "github.com/swaggo/files"
ginSwagger "github.com/swaggo/gin-swagger"
)
r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
// Echo
r.GET("/swagger/*", echoSwagger.WrapHandler)
// Fiber
app.Get("/swagger/*", fiberSwagger.WrapHandler(swaggerFiles.Handler))
// Chi / net/http
mux.Handle("/swagger/", httpSwagger.Handler(swaggerFiles.Handler))
Import the generated spec:
import _ "github.com/acme/myapi/docs" // blank: just register
import docs "github.com/acme/myapi/docs" // named: override host at runtime
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):
// @title Orders API
// @version 1.0
// @description Orders, customers, shipments.
// @contact.name API Support
// @contact.email [email protected]
// @license.name Apache-2.0
// @host api.acme.example
// @BasePath /api/v1
// @schemes https http
// @securityDefinitions.apikey Bearer
// @in header
// @name Authorization
// @description Use "Bearer <token>"
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
// GetOrder godoc
// @Summary Get an order by ID
// @Tags orders
// @Produce json
// @Param id path string true "Order ID (UUID)"
// @Success 200 {object} api.OrderResponse
// @Failure 404 {object} api.ErrorResponse
// @Router /orders/{id} [get]
// @Security Bearer
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:
// @Security Bearer
// @Security OAuth2[read, write]
// @Security BasicAuth && Bearer // both required (AND)
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
-
swag initruns clean (no warnings) -
docs/is committed and up-to-date with handlers - Every handler has
@Summary,@Router, and at least one@Success - Every protected handler has
@Security - Request bodies are named structs (no
map, no primitives) - Generic / nested response wrappers are spelled correctly (
Response[T]orResponse{data=T}) -
/swagger/*is gated in production (env flag or auth middleware) - CI fails when
docs/drifts from annotations
References
- references/swag-cli.md — CLI flags, parsing options, Makefile patterns
- references/annotations.md — full annotation grammar with examples
- references/struct-tags.md — type overrides, time/UUID/decimal handling
- references/anti-patterns.md — detailed walkthrough of each failure mode