Documentação de API com Swagger e swaggo

1. Introdução ao Swagger e swaggo no ecossistema Go

Swagger (agora OpenAPI) é um padrão amplamente adotado para descrever, produzir, consumir e visualizar serviços RESTful. Uma API bem documentada reduz drasticamente o atrito entre equipes de front-end, back-end e terceiros que consomem seus endpoints.

No ecossistema Go, o swaggo se destaca como a ferramenta mais madura para geração automática de documentação OpenAPI 2.0 (Swagger) a partir de comentários anotados diretamente no código-fonte. Diferente de alternativas como swagger-codegen (que gera código a partir de um schema) ou documentação manual, o swaggo mantém a documentação sincronizada com o código real, eliminando inconsistências.

2. Configuração inicial do projeto com swaggo

Primeiro, instale a ferramenta swag:

go install github.com/swaggo/swag/cmd/swag@latest

Adicione as dependências ao seu projeto. Usaremos Gin como framework web:

go get -u github.com/gin-gonic/gin
go get -u github.com/swaggo/gin-swagger
go get -u github.com/swaggo/files
go get -u github.com/swaggo/swag

Estrutura de diretórios recomendada:

meu-projeto/
├── cmd/
│   └── main.go
├── docs/
├── handlers/
│   └── usuario.go
├── models/
│   └── usuario.go
└── go.mod

Execute swag init na raiz do projeto para gerar a pasta docs/ com os arquivos docs.go, swagger.json e swagger.yaml.

3. Anotações essenciais para documentação de endpoints

As anotações são comentários Go posicionados imediatamente antes da função do handler. Veja os principais:

// @Summary      Listar usuários
// @Description  Retorna uma lista paginada de todos os usuários cadastrados
// @Tags         Usuários
// @Accept       json
// @Produce      json
// @Param        pagina   query     int  false  "Número da página"  default(1)
// @Param        limite   query     int  false  "Itens por página"  default(10)
// @Success      200  {array}   models.Usuario
// @Failure      400  {object}  models.ErroAPI
// @Failure      500  {object}  models.ErroAPI
// @Router       /usuarios [get]
func ListarUsuarios(c *gin.Context) {
    // implementação
}
  • @Summary: título curto do endpoint
  • @Description: descrição detalhada
  • @Param: parâmetros (formato: nome, tipo, tipo de dado, obrigatório, descrição)
  • @Success e @Failure: códigos HTTP e tipos de retorno
  • @Router: caminho e método HTTP

4. Modelos e tipos de dados com anotações Go

Defina structs com tags JSON e anotações swaggo para enriquecer a documentação:

package models

// Usuario representa um usuário do sistema
type Usuario struct {
    ID        uint      `json:"id" example:"1"`
    Nome      string    `json:"nome" example:"João Silva"`
    Email     string    `json:"email" example:"joao@email.com"`
    Idade     int       `json:"idade" example:"30" minimum:"18" maximum:"120"`
    Ativo     bool      `json:"ativo" example:"true"`
    DataCriacao time.Time `json:"data_criacao" example:"2024-01-15T10:30:00Z"`
    Perfil    Perfil    `json:"perfil" swaggertype:"object"`
}

// Perfil contém informações adicionais do usuário
type Perfil struct {
    Bio     string   `json:"bio" example:"Desenvolvedor Go"`
    Tags    []string `json:"tags" example:"golang,api,swagger"`
    Nivel   int      `json:"nivel" example:"3" enums:"1,2,3,4,5"`
}

// ErroAPI representa uma resposta de erro padronizada
type ErroAPI struct {
    Codigo  int    `json:"codigo" example:"400"`
    Mensagem string `json:"mensagem" example:"Parâmetro inválido"`
}
  • Tags example fornecem valores de exemplo no Swagger UI
  • Tags minimum, maximum e enums geram validações automáticas
  • swaggertype:"object" força a representação correta de tipos aninhados

5. Documentação avançada: segurança e metadados

Configure metadados globais no arquivo main.go:

// @title           API de Usuários
// @version         1.0.0
// @description     API REST para gerenciamento de usuários com autenticação JWT
// @termsOfService  http://swagger.io/terms/

// @contact.name   Suporte Técnico
// @contact.url    http://exemplo.com/suporte
// @contact.email  suporte@exemplo.com

// @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 Token JWT no formato "Bearer {token}"
func main() {
    // ...
}

Para proteger endpoints específicos:

// @Security BearerAuth
func CriarUsuario(c *gin.Context) {
    // implementação
}

6. Servindo a documentação interativa com Swagger UI

Integre o Swagger UI ao seu servidor Gin:

package main

import (
    "github.com/gin-gonic/gin"
    swaggerFiles "github.com/swaggo/files"
    ginSwagger "github.com/swaggo/gin-swagger"

    _ "seu-modulo/docs" // importe o pacote gerado
)

func main() {
    r := gin.Default()

    // Configuração do Swagger
    r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))

    // Seus endpoints
    api := r.Group("/api/v1")
    {
        api.GET("/usuarios", handlers.ListarUsuarios)
        api.POST("/usuarios", handlers.CriarUsuario)
        // ...
    }

    r.Run(":8080")
}

Acesse http://localhost:8080/swagger/index.html para visualizar a UI interativa. O arquivo JSON completo está disponível em /swagger/doc.json.

7. Boas práticas e automação do ciclo de vida

Crie um arquivo docs/docs.go para anotações gerais:

package docs

// Swagger metadata
// ...

Integre com go generate adicionando no início do main.go:

//go:generate swag init --parseDependency --parseInternal

Execute go generate ./... sempre que modificar anotações.

Use swag fmt para formatar automaticamente os comentários e swag validate para verificar erros na documentação gerada.

8. Exemplo completo: CRUD documentado com swaggo

package handlers

import (
    "net/http"
    "github.com/gin-gonic/gin"
    "seu-modulo/models"
)

// @Summary      Criar novo usuário
// @Description  Cadastra um novo usuário no sistema
// @Tags         Usuários
// @Accept       json
// @Produce      json
// @Param        usuario  body  models.Usuario  true  "Dados do usuário"
// @Success      201  {object}  models.Usuario
// @Failure      400  {object}  models.ErroAPI  "Dados inválidos"
// @Failure      409  {object}  models.ErroAPI  "Email já cadastrado"
// @Security     BearerAuth
// @Router       /usuarios [post]
func CriarUsuario(c *gin.Context) {
    var usuario models.Usuario
    if err := c.ShouldBindJSON(&usuario); err != nil {
        c.JSON(http.StatusBadRequest, models.ErroAPI{
            Codigo:  400,
            Mensagem: "Erro ao processar requisição: " + err.Error(),
        })
        return
    }
    // lógica de criação...
    c.JSON(http.StatusCreated, usuario)
}

// @Summary      Atualizar usuário
// @Description  Atualiza dados de um usuário existente
// @Tags         Usuários
// @Accept       json
// @Produce      json
// @Param        id       path      int               true  "ID do usuário"
// @Param        usuario  body      models.Usuario    true  "Dados atualizados"
// @Success      200  {object}  models.Usuario
// @Failure      400  {object}  models.ErroAPI
// @Failure      404  {object}  models.ErroAPI  "Usuário não encontrado"
// @Security     BearerAuth
// @Router       /usuarios/{id} [put]
func AtualizarUsuario(c *gin.Context) {
    // implementação
}

// @Summary      Excluir usuário
// @Description  Remove um usuário do sistema
// @Tags         Usuários
// @Produce      json
// @Param        id   path      int  true  "ID do usuário"
// @Success      204  "Sem conteúdo"
// @Failure      404  {object}  models.ErroAPI
// @Security     BearerAuth
// @Router       /usuarios/{id} [delete]
func ExcluirUsuario(c *gin.Context) {
    // implementação
}

Após executar swag init e iniciar o servidor, a interface do Swagger UI exibirá todos os endpoints com seus parâmetros, modelos de dados e esquemas de segurança perfeitamente documentados.

Referências