Capítulo 18: Documentação de API Swagger com Swag e Gin-Swagger
Especialização em Backend com Go & Gin • Gin Framework & Go 1.22+ • GORM, Clean Architecture, Concorrência e Alta Performance
🗺️ Mapa Conceitual do Tópico
flowchart TD
A["Código Go: Handlers e DTOs com Anotações Swag (@Summary, @Param, @Success)"] --> B["CLI swag init (Parsing Léxico da AST de Go)"]
B --> C["Gera Pacote 'docs/'"]
C --> D["docs/swagger.json"]
C --> E["docs/swagger.yaml"]
C --> F["docs/docs.go (Registro Global via init())"]
F --> G["Import em Branco no main.go: _ 'meu-modulo/docs'"]
subgraph GIN_ENGINE["Gin Engine (Exposição de Rota HTTP)"]
G --> H["r.GET('/swagger/*any', ginSwagger.WrapHandler(swaggerFiles.Handler))"]
end
H --> I["Navegador Web / Desenvolvedor Externo"]
I --> J["Interface Interativa Swagger UI"]
J --> K["Botão 'Authorize' (JWT Bearer Token Injetado)"]
J --> L["Testes 'Try it out' Diretos contra a API"]
style A fill:#e1f5fe,stroke:#03a9f4,stroke-width:2px
style B fill:#fff3e0,stroke:#ff9800,stroke-width:2px
style C fill:#ede7f6,stroke:#7e57c2,stroke-width:2px
style D fill:#ede7f6,stroke:#7e57c2,stroke-width:2px
style E fill:#ede7f6,stroke:#7e57c2,stroke-width:2px
style F fill:#e8f5e9,stroke:#4caf50,stroke-width:2px
style G fill:#fce4ec,stroke:#e91e63,stroke-width:2px
style H fill:#e8f5e9,stroke:#4caf50,stroke-width:2px
style I fill:#f3e5f5,stroke:#9c27b0,stroke-width:2px
style J fill:#c8e6c9,stroke:#2e7d32,stroke-width:2px
style K fill:#fffde7,stroke:#fbc02d,stroke-width:2px
style L fill:#c8e6c9,stroke:#2e7d32,stroke-width:2px
🏛️ 1. Documentação como Código (Docs-as-Code) com swag
Em equipes ágeis, manter a documentação da API em wikis manuais (Confluence, Notion) ou em arquivos JSON/YAML separados do código-fonte quase invariavelmente resulta em especificações obsoletas: um desenvolvedor altera o formato de um campo no handler e esquece de atualizar a documentação externa.
O ecossistema Go adota o princípio de Docs-as-Code através da biblioteca github.com/swaggo/swag:
- A especificação OpenAPI 3.0 / Swagger 2.0 é declarada através de comentários estruturados diretamente acima de cada função de handler Go.
- Durante o build, o utilitário de linha de comando
swag initinspeciona a Árvore Sintática Abstrata (AST) do Go, reflete sobre os tipos de dados das structs DTO e gera automaticamente os arquivos de esquema. - Como o código e os comentários residem no mesmo arquivo, alterações de contrato são revisadas obrigatoriamente no mesmo Pull Request.
📋 2. Sintaxe Canônica das Anotações Swag por Handler
A DSL do swag utiliza palavras-chave posicionais padronizadas:
| Anotação | Sintaxe e Exemplo | Finalidade na Especificação OpenAPI |
|---|---|---|
@Summary |
@Summary Obter detalhes do produto |
Título curto e conciso do endpoint exibido na listagem do Swagger UI. |
@Description |
@Description Retorna o registro completo... |
Explicação aprofundada de regras de negócio, precondições e efeitos. |
@Tags |
@Tags Produtos, Catálogo |
Agrupa os endpoints em seções temáticas colapsáveis na interface. |
@Accept |
@Accept json |
MIME type aceito no corpo da requisição (application/json). |
@Produce |
@Produce json |
MIME type retornado na resposta HTTP (application/json). |
@Param |
@Param id path int true "ID do produto" |
Descreve parâmetros de rota (path), query, header ou body. |
@Success |
@Success 200 {object} dto.ProdutoResponse |
Mapeia o código HTTP de sucesso diretamente para uma struct Go real. |
@Failure |
@Failure 404 {object} dto.ErroPadrao |
Descreve payloads estruturados de erro para cada código HTTP. |
@Security |
@Security BearerAuth |
Exige autorização via token JWT e adiciona ícone de cadeado. |
@Router |
@Router /api/v1/produtos/{id} [get] |
Caminho do endpoint e método HTTP correspondente. |
package handlers
import (
"net/http"
"strconv"
"github.com/gin-gonic/gin"
"meu-modulo/dto"
)
// ObterProdutoPorID godoc
// @Summary Buscar produto por ID
// @Description Retorna os detalhes cadastrais completos de um produto ativo
// @Tags Produtos
// @Accept json
// @Produce json
// @Param id path int true "Identificador numérico único do produto" example(42)
// @Success 200 {object} dto.ProdutoResponse "Produto localizado com sucesso"
// @Failure 400 {object} dto.ErroResponse "ID inválido ou malformado"
// @Failure 404 {object} dto.ErroResponse "Produto não encontrado no catálogo"
// @Failure 500 {object} dto.ErroResponse "Falha interna de infraestrutura"
// @Security BearerAuth
// @Router /produtos/{id} [get]
func ObterProdutoPorID(c *gin.Context) {
idParam := c.Param("id")
id, err := strconv.Atoi(idParam)
if err != nil || id <= 0 {
c.JSON(http.StatusBadRequest, dto.ErroResponse{Mensagem: "O identificador informado deve ser um inteiro positivo"})
return
}
// Executa a busca através do serviço
produto, err := servico.BuscarPorID(c.Request.Context(), uint(id))
if err != nil {
c.JSON(http.StatusNotFound, dto.ErroResponse{Mensagem: "Produto não encontrado"})
return
}
c.JSON(http.StatusOK, produto)
}
🔒 3. Definição Global de Autenticação JWT no main.go
Para que o botão interativo Authorize apareça no topo da interface gráfica do Swagger UI (permitindo que desenvolvedores colem o token JWT e realizem chamadas reais autenticadas), devemos declarar a definição de segurança global sobre a função main:
package main
import (
"github.com/gin-gonic/gin"
swaggerFiles "github.com/swaggo/files"
ginSwagger "github.com/swaggo/gin-swagger"
_ "meu-modulo/docs" // Import em branco obrigatório para registrar os esquemas gerados
)
// @title API Corporativa de Alta Performance
// @version 2.0.0
// @description Plataforma de microsserviços desenvolvida em Go 1.22+ e Gin Framework.
// @contact.name Equipe de Engenharia Backend
// @contact.email engenharia@empresa.com.br
// @host api.empresa.com.br
// @BasePath /api/v1
// @securityDefinitions.apikey BearerAuth
// @in header
// @name Authorization
// @description Insira o token JWT com o prefixo 'Bearer ': ex: Bearer eyJhbG...
func main() {
r := gin.Default()
// Exposição da rota do Swagger UI
r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
r.Run(":8080")
}
⚠️ Atenção: O import anônimo
_ "meu-modulo/docs"é estritamente obrigatório. Sem ele, o pacote compilado não registrará as definições do Swagger no init global, fazendo com que a UI carregue em branco com erroFailed to load resource: 404.
🛡️ 4. Segurança em Produção e CI/CD Gate
- Desativação em Produção Aberta: A rota
/swagger/*anyexpõe todos os detalhes estruturais da sua API. Em produção de serviços fechados, proteja a rota com um middleware de autenticação interna básica ou desative o registro da rota via variável de ambiente:if os.Getenv("ENV") != "production" { r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) } - Gate Automatizado de CI/CD: Para garantir que nenhum desenvolvedor altere uma rota ou struct DTO sem atualizar os arquivos em
docs/, adicione uma etapa no GitHub Actions:swag init git diff --exit-code docs/ || (echo "ERRO: O Swagger está desatualizado! Execute 'swag init' e comite as alterações." && exit 1)