Pular para o conteúdo

Trilha de Go · parte 25 de 37

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

Tamanho da fonte:
Largura da coluna:

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.

Pipeline de Geração de Documentação Swagger em Go
figura 1 · Pipeline de Geração de Documentação Swagger em Go

Fases do Fluxo:

  1. Docstrings Declarativas: Engenheiros anotam os handlers Go com tags padronizadas (@Summary, @Param, @Success, @Security).
  2. 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 arquivos swagger.json e swagger.yaml.
  3. Import Anônimo: A aplicação importa o pacote gerado (_ "meu-projeto/docs") para registrar os esquemas no runtime.
  4. Swagger UI: A biblioteca http-swagger intercepta 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:

Mapeamento entre Anotações Swag e OpenAPI UI
figura 2 · Mapeamento entre Anotações Swag e OpenAPI UI

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

TagFinalidadeExemplo de Sintaxe
@SummaryTítulo curto do endpoint exibido na listagem@Summary Listar Pedidos
@DescriptionExplicação detalhada do comportamento e regras@Description Retorna lista paginada de pedidos do usuário
@TagsAgrupamento de rotas por domínio@Tags Pedidos
@AcceptMIME type aceito no corpo da requisição@Accept json ou @Accept multipart/form-data
@ProduceMIME type devolvido na resposta@Produce json
@ParamDeclaração de parâmetro (path, query, header, body)@Param limit query int false "Limite de itens" default(20)
@SuccessResposta de sucesso (status, tipo, descrição)@Success 200 {array} dto.ProductOutput
@FailureRespostas de erro (status, tipo, descrição)@Failure 404 {object} dto.ErrorResponse
@SecurityMecanismo de segurança exigido@Security BearerAuth
@RouterRota 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

  1. Agrupamento por Tags: Organize seus endpoints usando @Tags coesas (Autenticação, Produtos, Faturamento). Isso transforma uma lista confusa de 50 rotas em seções navegáveis.
  2. 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.
  3. 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.go com @title, @version e @securityDefinitions.apikey.
  • Mapeie parâmetros de entrada com @Param e respostas de sucesso/erro com @Success e @Failure.
  • Nunca exponha entidades de banco de dados diretamente; utilize structs de DTO desacopladas.
  • Sirva a interface interativa com http-swagger na 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.

↑ Voltar ao topo

Atalhos de teclado

Abrir busca
/
Alternar tema claro/escuro
t
Aula anterior na série
←
Próxima aula na série
→
Lista de atalhos
?