Adicionando Swagger à sua API em Go
Geração automática de documentos OpenAPI a partir de anotações de código
A documentação de API é fundamental para qualquer aplicação moderna, e para APIs Go com Swagger (OpenAPI) tornou-se o padrão da indústria. Para desenvolvedores Go, a swaggo fornece uma solução elegante para gerar documentação de API abrangente diretamente a partir de anotações no código.
Esta bela imagem é gerada pelo modelo de IA Flux 1 dev.
Por que o Swagger é importante para APIs Go
Ao construir APIs REST, a documentação muitas vezes se torna desatualizada à medida que o código evolui. O Swagger resolve isso gerando a documentação a partir do seu código-fonte, garantindo que ela permaneça sincronizada com a sua implementação. A interface Swagger interativa permite que os desenvolvedores testem endpoints diretamente do navegador, melhorando significativamente a experiência de desenvolvimento.
Para equipes que constroem microsserviços ou APIs públicas, a documentação do Swagger torna-se essencial para:
- Geração de Clientes: Criar automaticamente bibliotecas de cliente em múltiplas linguagens
- Testes de Contrato: Validar requisições e respostas contra esquemas definidos
- Colaboração de Equipe: Fornecer uma única fonte de verdade para contratos de API
- Integração de Novos Desenvolvedores: Novos membros da equipe podem explorar as APIs de forma interativa
Primeiros Passos com swaggo
A biblioteca swaggo é a ferramenta mais popular para adicionar suporte a Swagger em aplicações Go. Ela funciona analisando comentários especiais no seu código e gerando arquivos de especificação OpenAPI 3.0.
Instalação
Primeiro, instale a ferramenta de linha de comando swag:
go install github.com/swaggo/swag/cmd/swag@latest
Em seguida, adicione o pacote de middleware Swagger apropriado para o seu framework. Para Gin:
go get -u github.com/swaggo/gin-swagger
go get -u github.com/swaggo/files
Para Echo:
go get -u github.com/swaggo/echo-swagger
Para Fiber:
go get -u github.com/gofiber/swagger
Configuração Básica
Comece adicionando informações gerais da API no seu arquivo main.go. Assim como você estruturaria uma API REST em Go, as anotações devem ser claras e descritivas:
// @title Product API
// @version 1.0
// @description A product management API with Swagger documentation
// @termsOfService http://swagger.io/terms/
// @contact.name API Support
// @contact.url http://www.swagger.io/support
// @contact.email support@swagger.io
// @license.name Apache 2.0
// @license.url http://www.apache.org/licenses/LICENSE-2.0.html
// @host localhost:8080
// @BasePath /api/v1
// @securityDefinitions.apikey Bearer
// @in header
// @name Authorization
// @description Type "Bearer" followed by a space and JWT token.
func main() {
// Seu código da aplicação
}
Implementação com o Framework Gin
Vamos implementar um exemplo completo usando Gin. Primeiro, defina seus modelos de dados com tags de estrutura:
type Product struct {
ID int `json:"id" example:"1"`
Name string `json:"name" example:"Laptop" binding:"required"`
Description string `json:"description" example:"High-performance laptop"`
Price float64 `json:"price" example:"999.99" binding:"required,gt=0"`
Stock int `json:"stock" example:"50"`
}
type ErrorResponse struct {
Error string `json:"error" example:"Invalid input"`
Message string `json:"message" example:"Product name is required"`
}
Agora, anote suas funções de handler. Ao trabalhar com operações de banco de dados, essas anotações ajudam a documentar o fluxo de dados:
// GetProduct godoc
// @Summary Get product by ID
// @Description Retrieve a single product by its unique identifier
// @Tags products
// @Accept json
// @Produce json
// @Param id path int true "Product ID"
// @Success 200 {object} Product
// @Failure 400 {object} ErrorResponse
// @Failure 404 {object} ErrorResponse
// @Router /products/{id} [get]
func GetProduct(c *gin.Context) {
id := c.Param("id")
// Implementação aqui
c.JSON(200, Product{ID: 1, Name: "Laptop", Price: 999.99})
}
// CreateProduct godoc
// @Summary Create a new product
// @Description Add a new product to the catalog
// @Tags products
// @Accept json
// @Produce json
// @Param product body Product true "Product object"
// @Success 201 {object} Product
// @Failure 400 {object} ErrorResponse
// @Security Bearer
// @Router /products [post]
func CreateProduct(c *gin.Context) {
var product Product
if err := c.ShouldBindJSON(&product); err != nil {
c.JSON(400, ErrorResponse{Error: "Bad Request", Message: err.Error()})
return
}
// Salvar no banco de dados
c.JSON(201, product)
}
Gerando Documentação
Após anotar seu código, gere a documentação do Swagger:
swag init
Isso cria uma pasta docs com swagger.json, swagger.yaml e arquivos Go. Importe e registre o endpoint Swagger:
package main
import (
"github.com/gin-gonic/gin"
swaggerFiles "github.com/swaggo/files"
ginSwagger "github.com/swaggo/gin-swagger"
_ "yourproject/docs" // Importa docs gerados
)
func main() {
r := gin.Default()
// Rotas da API
v1 := r.Group("/api/v1")
{
v1.GET("/products/:id", GetProduct)
v1.POST("/products", CreateProduct)
}
// Endpoint Swagger
r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
r.Run(":8080")
}
Agora, acesse sua documentação de API interativa em http://localhost:8080/swagger/index.html.
Implementação com o Framework Echo
Usuários do Echo seguem um padrão semelhante, mas com middleware específico do Echo:
package main
import (
"github.com/labstack/echo/v4"
echoSwagger "github.com/swaggo/echo-swagger"
_ "yourproject/docs"
)
func main() {
e := echo.New()
// Rotas da API
api := e.Group("/api/v1")
api.GET("/products/:id", getProduct)
api.POST("/products", createProduct)
// Endpoint Swagger
e.GET("/swagger/*", echoSwagger.WrapHandler)
e.Start(":8080")
}
Implementação com o Framework Fiber
A implementação do Fiber é igualmente direta:
package main
import (
"github.com/gofiber/fiber/v2"
"github.com/gofiber/swagger"
_ "yourproject/docs"
)
func main() {
app := fiber.New()
// Rotas da API
api := app.Group("/api/v1")
api.Get("/products/:id", getProduct)
api.Post("/products", createProduct)
// Endpoint Swagger
app.Get("/swagger/*", swagger.HandlerDefault)
app.Listen(":8080")
}
Anotações Avançadas de Swagger
Documentando Corpos de Requisição Complexos
Para estruturas aninhadas ou arrays:
type CreateOrderRequest struct {
CustomerID int `json:"customer_id" example:"123" binding:"required"`
Items []OrderItem `json:"items" binding:"required,min=1"`
ShippingAddress Address `json:"shipping_address" binding:"required"`
}
type OrderItem struct {
ProductID int `json:"product_id" example:"1" binding:"required"`
Quantity int `json:"quantity" example:"2" binding:"required,min=1"`
}
type Address struct {
Street string `json:"street" example:"123 Main St" binding:"required"`
City string `json:"city" example:"New York" binding:"required"`
ZipCode string `json:"zip_code" example:"10001" binding:"required"`
}
// CreateOrder godoc
// @Summary Create a new order
// @Description Create an order with multiple items and shipping information
// @Tags orders
// @Accept json
// @Produce json
// @Param order body CreateOrderRequest true "Order details"
// @Success 201 {object} Order
// @Failure 400 {object} ErrorResponse
// @Failure 422 {object} ErrorResponse
// @Security Bearer
// @Router /orders [post]
func CreateOrder(c *gin.Context) {
// Implementação
}
Documentando Uploads de Arquivo
// UploadImage godoc
// @Summary Upload product image
// @Description Upload an image file for a product
// @Tags products
// @Accept multipart/form-data
// @Produce json
// @Param id path int true "Product ID"
// @Param file formData file true "Image file"
// @Success 200 {object} map[string]string
// @Failure 400 {object} ErrorResponse
// @Security Bearer
// @Router /products/{id}/image [post]
func UploadImage(c *gin.Context) {
file, _ := c.FormFile("file")
// Processar upload
}
Parâmetros de Consulta e Paginação
// ListProducts godoc
// @Summary List products with pagination
// @Description Get paginated list of products with optional filtering
// @Tags products
// @Accept json
// @Produce json
// @Param page query int false "Page number" default(1)
// @Param page_size query int false "Items per page" default(10)
// @Param category query string false "Filter by category"
// @Param min_price query number false "Minimum price"
// @Param max_price query number false "Maximum price"
// @Success 200 {array} Product
// @Failure 400 {object} ErrorResponse
// @Router /products [get]
func ListProducts(c *gin.Context) {
// Implementação com paginação
}
Autenticação e Segurança
Documente diferentes métodos de autenticação na sua API. Para aplicações multi-tenant, a documentação adequada da autenticação é crucial:
Autenticação com Token Bearer
// @securityDefinitions.apikey Bearer
// @in header
// @name Authorization
// @description Type "Bearer" followed by a space and JWT token.
Autenticação com Chave de API
// @securityDefinitions.apikey ApiKeyAuth
// @in header
// @name X-API-Key
// @description API key for authentication
Autenticação OAuth2
// @securitydefinitions.oauth2.application OAuth2Application
// @tokenUrl https://example.com/oauth/token
// @scope.write Grants write access
// @scope.admin Grants read and write access to administrative information
Autenticação Básica
// @securityDefinitions.basic BasicAuth
Aplique segurança a endpoints específicos:
// @Security Bearer
// @Security ApiKeyAuth
Personalizando a Interface Swagger
Você pode personalizar a aparência e o comportamento da interface Swagger:
// Configuração personalizada
url := ginSwagger.URL("http://localhost:8080/swagger/doc.json")
r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler, url))
// Com título personalizado
r.GET("/swagger/*any", ginSwagger.WrapHandler(
swaggerFiles.Handler,
ginSwagger.URL("http://localhost:8080/swagger/doc.json"),
ginSwagger.DefaultModelsExpandDepth(-1),
))
Para desativar o Swagger em produção:
if os.Getenv("ENV") != "production" {
r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
}
Integrando com CI/CD
Automatize a geração da documentação do Swagger no seu pipeline de CI/CD:
# Exemplo de GitHub Actions
name: Generate Swagger Docs
on: [push]
jobs:
swagger:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: '1.21'
- name: Install swag
run: go install github.com/swaggo/swag/cmd/swag@latest
- name: Generate Swagger docs
run: swag init
- name: Commit docs
run: |
git config user.name github-actions
git config user.email github-actions@github.com
git add docs/
git commit -m "Update Swagger documentation" || exit 0
git push
Melhores Práticas
1. Estilo de Anotação Consistente
Mantenha um formato consistente em todos os endpoints:
// HandlerName godoc
// @Summary Brief description (under 50 chars)
// @Description Detailed description of what the endpoint does
// @Tags resource-name
// @Accept json
// @Produce json
// @Param name location type required "description"
// @Success 200 {object} ResponseType
// @Failure 400 {object} ErrorResponse
// @Router /path [method]
2. Use Exemplos Descritivos
Adicione exemplos realistas para ajudar os consumidores da API:
type User struct {
ID int `json:"id" example:"1"`
Email string `json:"email" example:"user@example.com"`
CreatedAt time.Time `json:"created_at" example:"2025-01-15T10:30:00Z"`
}
3. Documente Todos os Códigos de Resposta
Inclua todos os possíveis códigos de status HTTP:
// @Success 200 {object} Product
// @Success 201 {object} Product
// @Failure 400 {object} ErrorResponse "Bad Request"
// @Failure 401 {object} ErrorResponse "Unauthorized"
// @Failure 403 {object} ErrorResponse "Forbidden"
// @Failure 404 {object} ErrorResponse "Not Found"
// @Failure 422 {object} ErrorResponse "Validation Error"
// @Failure 500 {object} ErrorResponse "Internal Server Error"
4. Versione Sua API
Use versionamento adequado no caminho base:
// @BasePath /api/v1
E organize seu código conforme:
v1 := r.Group("/api/v1")
v2 := r.Group("/api/v2")
5. Agrupe Endpoints Relacionados
Use tags para organizar endpoints logicamente:
// @Tags products
// @Tags orders
// @Tags users
6. Mantenha a Documentação Atualizada
Execute swag init antes de cada commit ou integre-o ao seu processo de build:
#!/bin/bash
# hook pre-commit
swag init
git add docs/
Testando Documentação Swagger
Ao trabalhar com arquiteturas serverless como AWS Lambda, testar sua documentação de API torna-se ainda mais importante:
func TestSwaggerGeneration(t *testing.T) {
// Verificar se swagger.json existe
_, err := os.Stat("./docs/swagger.json")
if err != nil {
t.Fatal("swagger.json not found, run 'swag init'")
}
// Verificar se o endpoint swagger responde
r := setupRouter()
w := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/swagger/index.html", nil)
r.ServeHTTP(w, req)
assert.Equal(t, 200, w.Code)
}
Problemas Comuns e Soluções
Documentação Não Atualizando
Se as alterações não aparecerem, verifique se você está regenerando a documentação:
swag init --parseDependency --parseInternal
O flag --parseDependency analisa dependências externas, e --parseInternal analisa pacotes internos.
Tipos Personalizados Não Reconhecidos
Para tipos de pacotes externos, use a tag swaggertype:
type CustomTime struct {
time.Time
}
func (CustomTime) SwaggerDoc() map[string]string {
return map[string]string{
"time": "RFC3339 timestamp",
}
}
Ou use a tag swaggertype:
type Product struct {
ID int `json:"id"`
UpdatedAt CustomTime `json:"updated_at" swaggertype:"string" format:"date-time"`
}
Arrays e Enumerações
Documente tipos de array e enumerações:
type Filter struct {
Status []string `json:"status" enums:"active,inactive,pending"`
Tags []string `json:"tags"`
}
// @Param status query string false "Status filter" Enums(active, inactive, pending)
Abordagens Alternativas
Embora a swaggo seja a escolha mais popular, existem outras opções:
go-swagger
Uma alternativa mais rica em funcionalidades, mas complexa:
brew install go-swagger
swagger generate spec -o ./swagger.json
Arquivos OpenAPI Manuais
Para controle total, escreva especificações OpenAPI manualmente em YAML:
openapi: 3.0.0
info:
title: Product API
version: 1.0.0
paths:
/products:
get:
summary: List products
responses:
'200':
description: Success
Em seguida, sirva com:
r.StaticFile("/openapi.yaml", "./openapi.yaml")
Integrando com IA e LLMs
Ao construir APIs que se integram com serviços de IA, uma documentação adequada torna-se crucial. Por exemplo, ao trabalhar com saídas estruturadas de LLMs, o Swagger ajuda a documentar esquemas complexos de requisição e resposta:
type LLMRequest struct {
Prompt string `json:"prompt" example:"Summarize this text"`
Model string `json:"model" example:"qwen2.5:latest"`
Temperature float64 `json:"temperature" example:"0.7" minimum:"0" maximum:"2"`
MaxTokens int `json:"max_tokens" example:"1000" minimum:"1"`
Schema map[string]interface{} `json:"schema,omitempty"`
}
// GenerateStructured godoc
// @Summary Generate structured LLM output
// @Description Generate text with constrained output schema
// @Tags llm
// @Accept json
// @Produce json
// @Param request body LLMRequest true "LLM parameters"
// @Success 200 {object} map[string]interface{}
// @Failure 400 {object} ErrorResponse
// @Router /llm/generate [post]
func GenerateStructured(c *gin.Context) {
// Implementação
}
Considerações de Desempenho
A documentação do Swagger tem um impacto mínimo no desempenho:
- Tempo de Build:
swag initleva de 1 a 3 segundos para a maioria dos projetos - Tempo de Execução: A documentação é carregada uma vez na inicialização
- Memória: Geralmente adiciona 1-2MB ao tamanho do binário
- Tempo de Resposta: Sem impacto nos próprios endpoints da API
Para APIs muito grandes (100+ endpoints), considere:
- Dividir em vários arquivos Swagger
- Carregamento sob demanda dos assets da interface Swagger
- Servir a documentação a partir de um serviço separado
Considerações de Segurança
Ao expor a documentação do Swagger:
- Desativar em Produção (se a API for interna):
if os.Getenv("ENV") == "production" {
// Não registrar o endpoint Swagger
return
}
- Adicionar Autenticação:
authorized := r.Group("/swagger")
authorized.Use(AuthMiddleware())
authorized.GET("/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
- Limitar a Taxa de Reclusão do Endpoint:
r.GET("/swagger/*any", RateLimitMiddleware(), ginSwagger.WrapHandler(swaggerFiles.Handler))
- Nunca Expor Detalhes Internos:
- Não documente endpoints internos
- Evite expor esquemas de banco de dados diretamente
- Sanitize as mensagens de erro na documentação
Conclusão
Adicionar documentação do Swagger à sua API Go transforma a experiência de desenvolvimento de palpites para exploração guiada. A biblioteca swaggo torna esse processo direto, gerando documentação OpenAPI abrangente a partir das suas anotações de código.
Principais pontos:
- Comece com anotações básicas e expanda gradualmente
- Mantenha a documentação sincronizada com o código por meio de CI/CD
- Use a interface Swagger para testes interativos durante o desenvolvimento
- Documente autenticação, erros e casos extremos detalhadamente
- Considere as implicações de segurança ao expor a documentação
Seja você construindo microsserviços, APIs públicas ou ferramentas internas, a documentação do Swagger rende dividendos na redução da carga de suporte, integração mais rápida e melhor design de API. O investimento inicial em aprender a sintaxe de anotação rapidamente se torna rotina, e a geração automatizada garante que sua documentação nunca fique para trás da sua implementação.
Para desenvolvedores Go, a combinação de tipagem forte, geração de código e o sistema de anotações da swaggo cria um fluxo de trabalho poderoso que torna a documentação de API uma parte natural do processo de desenvolvimento, em vez de uma consideração tardia.
Se a pilha HTTP subjacente ainda for uma questão em aberto, Frameworks Web em Go em 2026: net/http, chi, Gin, Echo, Fiber Comparados faz o benchmark das cinco opções na mesma carga de trabalho, permitindo que a decisão sobre o framework seja resolvida antes que a ferramenta de documentação seja conectada.
Links Úteis
- Guia Rápido de Go
- Construindo APIs REST em Go
- Frameworks Web em Go em 2026: net/http, chi, Gin, Echo, Fiber Comparados
- Comparando ORMs Go para PostgreSQL: GORM vs Ent vs Bun vs sqlc
- Padrões de Banco de Dados Multi-Tenant com exemplos em Go
- LLMs com Saída Estruturada: Ollama, Qwen3 & Python ou Go
- Desempenho da AWS Lambda: JavaScript vs Python vs Golang