Documentação de APIs com Swagger em Go: OpenAPI, Swag e Automação
Como gerar a documentação OpenAPI de uma API Go a partir de anotações no código com Swag, evitando documentação desatualizada.
Publicada em · 6 min de leitura
Documentação de APIs com Swagger em Go: OpenAPI, Swag e Automação
Documentar APIs manualmente através de ferramentas externas (como Postman collections desatualizadas ou planilhas) gera inevitavelmente drift de documentação: o código evolui, campos são renomeados, novos endpoints são criados e a documentação torna-se obsoleta, quebrando a comunicação entre times de frontend, mobile e parceiros externos.
No ecossistema Go, a abordagem dominante para manter documentações vivas e 100% sincronizadas com o código é o uso do Swag (github.com/swaggo/swag). O Swag analisa a Abstract Syntax Tree (AST) do Go e os comentários declarativos (docstrings) dos handlers, compilando automaticamente uma especificação OpenAPI 2.0 / 3.0 completa servida via Swagger UI interativo.
1. O Pipeline de Compilação do Swag
O Swag funciona como um compilador estático de documentação. Ele não depende de reflexão em tempo de execução nem adiciona overhead de latência às suas requisições HTTP normais.
Fases do Fluxo:
- Docstrings Declarativas: Engenheiros anotam os handlers Go com tags padronizadas (
@Summary,@Param,@Success,@Security). - Compilação com
swag init: O CLI do Swag lê o código-fonte, mapeia as structs de DTO (Request/Response) e gera um pacote Go estático (docs/docs.go) juntamente com os arquivosswagger.jsoneswagger.yaml. - Import Anônimo: A aplicação importa o pacote gerado (
_ "meu-projeto/docs") para registrar os esquemas no runtime. - Swagger UI: A biblioteca
http-swaggerintercepta a rota/swagger/*e renderiza a interface web interativa onde desenvolvedores e clientes podem testar requisições em tempo real.
2. Anatomia das Anotações Swag
O Swag traduz diretamente comentários de função em propriedades ricas da interface gráfica do Swagger:
3. Configuração Geral da Aplicação (main.go)
Antes de documentar endpoints específicos, declare os metadados globais da API diretamente acima da função main():
package main
import (
"net/http"
_ "meu-projeto/docs" // Import necessário para registrar os arquivos gerados
httpSwagger "github.com/swaggo/http-swagger/v2"
)
// @title API de E-Commerce e Pagamentos
// @version 1.0
// @description Microsserviço de gerenciamento de produtos, pedidos e checkout em Go.
// @termsOfService https://empresa.com.br/termos
// @contact.name Time de Plataforma Backend
// @contact.url https://empresa.com.br/suporte
// @contact.email eng@empresa.com.br
// @license.name Apache 2.0
// @license.url http://www.apache.org/licenses/LICENSE-2.0.html
// @host localhost:8080
// @BasePath /api/v1
// @securityDefinitions.apikey BearerAuth
// @in header
// @name Authorization
// @description Digite "Bearer " seguido pelo token JWT para autorizar requisições
func main() {
mux := http.NewServeMux()
// Registra a rota da documentação interativa
mux.Handle("/swagger/", httpSwagger.Handler(
httpSwagger.URL("/swagger/doc.json"), // URL do swagger.json
))
// ... inicialização das rotas de negócio
http.ListenAndServe(":8080", mux)
}
4. Modelagem de DTOs (Request / Response)
package dto
// CreateProductInput representa a carga útil enviada para cadastrar um produto
type CreateProductInput struct {
Name string `json:"name" example:"Monitor Dell 27 4K" binding:"required"`
Description string `json:"description" example:"Monitor IPS UHD com USB-C Hub"`
Price float64 `json:"price" example:"3499.90" binding:"required"`
Stock int `json:"stock" example:"50"`
}
// ProductOutput representa o payload devolvido nas consultas de produtos
type ProductOutput struct {
ID string `json:"id" example:"prod_99f2b8"`
Name string `json:"name" example:"Monitor Dell 27 4K"`
Price float64 `json:"price" example:"3499.90"`
Stock int `json:"stock" example:"50"`
CreatedAt string `json:"created_at" example:"2026-10-20T10:30:00Z"`
}
// ErrorResponse padroniza mensagens de erro da API
type ErrorResponse struct {
Code string `json:"code" example:"VALIDATION_ERROR"`
Message string `json:"message" example:"O preço informado deve ser superior a zero."`
}
5. Documentando Handlers com Anotações Detalhadas
Cada manipulador de requisição deve possuir anotações claras sobre seus parâmetros de entrada, tipos de dados aceitos e respostas possíveis:
package handler
import (
"encoding/json"
"net/http"
"meu-projeto/internal/dto"
)
type ProductHandler struct{}
// CreateProduct godoc
// @Summary Cadastrar novo produto
// @Description Adiciona um item ao catálogo de produtos da loja. Exige privilégios de administrador.
// @Tags Produtos
// @Accept json
// @Produce json
// @Param payload body dto.CreateProductInput true "Dados cadastrais do produto"
// @Success 201 {object} dto.ProductOutput "Produto cadastrado com sucesso"
// @Failure 400 {object} dto.ErrorResponse "Payload inválido ou campos obrigatórios ausentes"
// @Failure 401 {object} dto.ErrorResponse "Token de autenticação ausente ou inválido"
// @Failure 403 {object} dto.ErrorResponse "Usuário sem permissão de administrador"
// @Security BearerAuth
// @Router /products [post]
func (h *ProductHandler) CreateProduct(w http.ResponseWriter, r *http.Request) {
var input dto.CreateProductInput
if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusBadRequest)
_ = json.NewEncoder(w).Encode(dto.ErrorResponse{
Code: "INVALID_JSON",
Message: "JSON malformado",
})
return
}
// Lógica de persistência / caso de uso...
output := dto.ProductOutput{
ID: "prod_99f2b8",
Name: input.Name,
Price: input.Price,
Stock: input.Stock,
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusCreated)
_ = json.NewEncoder(w).Encode(output)
}
// GetProductByID godoc
// @Summary Buscar produto por ID
// @Description Recupera os detalhes completos de um produto através do seu identificador único.
// @Tags Produtos
// @Produce json
// @Param id path string true "ID do Produto" example(prod_99f2b8)
// @Success 200 {object} dto.ProductOutput "Produto localizado"
// @Failure 404 {object} dto.ErrorResponse "Produto não encontrado"
// @Router /products/{id} [get]
func (h *ProductHandler) GetProductByID(w http.ResponseWriter, r *http.Request) {
productID := r.PathValue("id") // Go 1.22+ ServeMux Path Value
if productID == "" {
http.Error(w, `{"error":"id_obrigatorio"}`, http.StatusBadRequest)
return
}
// ... busca no repositório
}
6. Principais Diretivas do Swag
| Tag | Finalidade | Exemplo de Sintaxe |
|---|---|---|
@Summary | Título curto do endpoint exibido na listagem | @Summary Listar Pedidos |
@Description | Explicação detalhada do comportamento e regras | @Description Retorna lista paginada de pedidos do usuário |
@Tags | Agrupamento de rotas por domínio | @Tags Pedidos |
@Accept | MIME type aceito no corpo da requisição | @Accept json ou @Accept multipart/form-data |
@Produce | MIME type devolvido na resposta | @Produce json |
@Param | Declaração de parâmetro (path, query, header, body) | @Param limit query int false "Limite de itens" default(20) |
@Success | Resposta de sucesso (status, tipo, descrição) | @Success 200 {array} dto.ProductOutput |
@Failure | Respostas de erro (status, tipo, descrição) | @Failure 404 {object} dto.ErrorResponse |
@Security | Mecanismo de segurança exigido | @Security BearerAuth |
@Router | Rota e método HTTP associado | @Router /orders [get] |
7. Automação no Ciclo de Vida: Makefile e CI/CD
Para garantir que a documentação nunca fique defasada em relação ao código, inclua a geração e validação do Swagger no Makefile e na pipeline de Integração Contínua:
Makefile
.PHONY: swagger
swagger:
@echo "==> Gerando documentação Swagger/OpenAPI..."
go run github.com/swaggo/swag/cmd/swag init -g cmd/api/main.go -o docs/
Validação no GitHub Actions (Detecção de Drift)
name: CI Verification
jobs:
check-swagger-drift:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: '1.23'
- name: Regenerate Swagger Docs
run: |
go run github.com/swaggo/swag/cmd/swag init -g cmd/api/main.go -o docs/
- name: Verify No Git Changes
run: |
if [ -n "$(git status --porcelain docs/)" ]; then
echo "ERRO: O código foi alterado sem atualizar a pasta docs/!"
echo "Execute 'make swagger' localmente e comite as alterações."
git diff docs/
exit 1
fi
8. Boas Práticas e Recomendações
- Agrupamento por Tags: Organize seus endpoints usando
@Tagscoesas (Autenticação,Produtos,Faturamento). Isso transforma uma lista confusa de 50 rotas em seções navegáveis. - Exemplos Reais (
example:"..."): Sempre adicione exemplos realistas nas tags de struct dos seus DTOs. Isso permite que os desenvolvedores front-end cliquem em “Try it out” e executem chamadas válidas imediatamente. - Desativação em Produção Crítica: Se sua API for estritamente interna e você não desejar expor o Swagger UI publicamente na internet, condicione o registro da rota
/swagger/a uma variável de ambiente:if os.Getenv("ENV") != "production" { mux.Handle("/swagger/", httpSwagger.Handler()) }
9. Resumo Conceitual
- O Swag compila docstrings estáticas em especificações OpenAPI sem nenhum impacto na performance de runtime.
- Declare os metadados globais da API na
main.gocom@title,@versione@securityDefinitions.apikey. - Mapeie parâmetros de entrada com
@Parame respostas de sucesso/erro com@Successe@Failure. - Nunca exponha entidades de banco de dados diretamente; utilize structs de DTO desacopladas.
- Sirva a interface interativa com
http-swaggerna rota/swagger/*. - Previna o esquecimento no time validando no CI com
git diff --exit-code docs/se a documentação sofreu drift. - Combine a documentação da sua API com Middlewares em Go, Autenticação e JWT e o roteamento de Servidor HTTP Nativo Moderno.