<h2>Entendendo APIs e a Importância da Documentação</h2>
<p>Uma API (Application Programming Interface) é o contrato entre seu servidor e seus clientes. Quando você cria uma API em Go, está definindo endpoints, métodos HTTP, formatos de requisição e resposta. A documentação de uma API não é um luxo — é uma necessidade fundamental. Sem ela, desenvolvedores que consumem sua API gastarão horas em tentativa e erro, abrindo issues desnecessários e tendo uma experiência frustrante.</p>
<p>A documentação tradicional (em arquivos Markdown, PDFs ou wikis) rapidamente fica desatualizada. Você muda um endpoint, adiciona um novo campo de validação, e a documentação permanece obsoleta. É aí que o Swagger entra em cena. O Swagger (agora chamado OpenAPI) é um padrão da indústria que permite documentar APIs de forma estruturada e automatizada. Melhor ainda: com o swaggo, você gera essa documentação diretamente a partir do seu código Go, usando anotações simples.</p>
<h2>O que é Swagger/OpenAPI e por que usar swaggo</h2>
<p>Swagger é uma especificação aberta que descreve APIs RESTful em formato YAML ou JSON. A especificação define todos os detalhes: quais endpoints existem, que métodos HTTP aceitam, quais são os parâmetros, como são estruturados os dados de entrada e saída, códigos de status HTTP, autenticação, e muito mais. Essa especificação pode ser lida por ferramentas que geram interfaces visuais interativas, permitindo que qualquer um explore e teste sua API sem escrever código.</p>
<p>O swaggo é uma ferramenta Go que lê anotações (comments especiais) no seu código-fonte e gera automaticamente a especificação Swagger/OpenAPI completa. Isso significa que sua documentação vive junto com seu código. Quando você muda uma função, atualiza a anotação ali mesmo, e a documentação se regenera. Não há sincronização manual, não há risco de divergência entre código e documentação.</p>
<h3>Instalação e Configuração Inicial</h3>
<p>Comece instalando o swaggo via go install. Você também precisará de um roteador HTTP em Go — neste artigo usaremos Gin, que é popular e simples, mas os conceitos aplicam-se a qualquer roteador.</p>
<pre><code class="language-bash">go install github.com/swaggo/swag/cmd/swag@latest</code></pre>
<p>Em seguida, inicialize um módulo Go e adicione as dependências necessárias:</p>
<pre><code class="language-bash">go mod init github.com/seu-usuario/sua-api
go get -u github.com/gin-gonic/gin
go get -u github.com/swaggo/gin-swagger
go get -u github.com/swaggo/files</code></pre>
<p>Crie a estrutura básica do seu projeto:</p>
<pre><code>seu-projeto/
├── main.go
├── handlers/
│ └── users.go
├── models/
│ └── user.go
└── go.mod</code></pre>
<h2>Estruturando sua API com anotações Swagger</h2>
<p>A magia do swaggo está nas anotações. Cada endpoint, cada modelo de dados, é documentado através de comentários especiais que seguem a sintaxe do Swagger. O swaggo lê essas anotações e gera a especificação OpenAPI automaticamente.</p>
<h3>Anotações Globais da API</h3>
<p>Comece definindo informações globais sobre sua API no arquivo main.go:</p>
<pre><code class="language-go">package main
import (
"github.com/gin-gonic/gin"
swaggerFiles "github.com/swaggo/files"
ginSwagger "github.com/swaggo/gin-swagger"
_ "github.com/seu-usuario/sua-api/docs"
)
// @title API de Gerenciamento de Usuários
// @version 1.0
// @description Uma API simples para demonstrar Swagger com swaggo
// @termsOfService http://swagger.io/terms/
// @contact.name API Support
// @contact.url http://www.swagger.io/support
// @license.name Apache 2.0
// @license.url http://www.apache.org/licenses/LICENSE-2.0.html
// @host localhost:8080
// @BasePath /api/v1
// @schemes http https
// @securityDefinitions.apikey Bearer
// @in header
// @name Authorization
func main() {
router := gin.Default()
// Rota para acessar a documentação Swagger
router.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
// Suas rotas de API aqui
api := router.Group("/api/v1")
{
api.POST("/users", CreateUser)
api.GET("/users/:id", GetUser)
api.PUT("/users/:id", UpdateUser)
api.DELETE("/users/:id", DeleteUser)
}
router.Run(":8080")
}</code></pre>
<p>As anotações no topo do main.go definem informações globais: título da API, versão, descrição, informações de contato, segurança (no caso, um Bearer token). O import <code>_ "github.com/seu-usuario/sua-api/docs"</code> é importante — ele carrega o pacote docs gerado pelo swaggo.</p>
<h3>Modelos de Dados com Tags Swagger</h3>
<p>Defina seus modelos de dados em <code>models/user.go</code>:</p>
<pre><code class="language-go">package models
// User representa um usuário no sistema
type User struct {
// ID único do usuário
// example: 1
ID int json:"id" example:"1"
// Nome completo do usuário
// example: João Silva
Name string json:"name" example:"João Silva"
// Email do usuário (deve ser único)
// example: joao@example.com
Email string json:"email" example:"joao@example.com"
// Idade do usuário
// example: 30
Age int json:"age" example:"30"
}
// CreateUserRequest representa os dados necessários para criar um usuário
type CreateUserRequest struct {
// Nome do usuário (obrigatório)
// minlength: 3
// maxlength: 100
Name string json:"name" binding:"required,min=3,max=100" example:"Maria Santos"
// Email do usuário (obrigatório)
Email string json:"email" binding:"required,email" example:"maria@example.com"
// Idade do usuário (obrigatório)
// minimum: 18
// maximum: 120
Age int json:"age" binding:"required,min=18,max=120" example:"25"
}</code></pre>
<p>Repare que não há tags especiais <code>swagger:</code> aqui. O swaggo é inteligente o suficiente para ler os tags JSON e os comentários acima dos campos.</p>
<h3>Endpoints com Documentação Detalhada</h3>
<p>Agora documente seus handlers em <code>handlers/users.go</code>:</p>
<pre><code class="language-go">package handlers
import (
"net/http"
"strconv"
"github.com/gin-gonic/gin"
"github.com/seu-usuario/sua-api/models"
)
// CreateUser cria um novo usuário
// @Summary Criar um novo usuário
// @Description Cria um novo usuário no sistema com os dados fornecidos
// @Tags users
// @Accept json
// @Produce json
// @Param request body models.CreateUserRequest true "Dados do usuário a ser criado"
// @Success 201 {object} models.User "Usuário criado com sucesso"
// @Failure 400 {object} map[string]string "Erro de validação"
// @Failure 500 {object} map[string]string "Erro interno do servidor"
// @Router /users [post]
// @Security Bearer
func CreateUser(c *gin.Context) {
var req models.CreateUserRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
user := models.User{
ID: 1, // Em produção, isso seria um ID gerado
Name: req.Name,
Email: req.Email,
Age: req.Age,
}
c.JSON(http.StatusCreated, user)
}
// GetUser obtém um usuário pelo ID
// @Summary Obter usuário por ID
// @Description Retorna os dados completos de um usuário específico
// @Tags users
// @Accept json
// @Produce json
// @Param id path int true "ID do usuário"
// @Success 200 {object} models.User "Usuário encontrado"
// @Failure 404 {object} map[string]string "Usuário não encontrado"
// @Router /users/{id} [get]
// @Security Bearer
func GetUser(c *gin.Context) {
id, err := strconv.Atoi(c.Param("id"))
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "ID inválido"})
return
}
// Simulação: retornar usuário
user := models.User{
ID: id,
Name: "João Silva",
Email: "joao@example.com",
Age: 30,
}
c.JSON(http.StatusOK, user)
}
// UpdateUser atualiza um usuário existente
// @Summary Atualizar usuário
// @Description Atualiza os dados de um usuário existente
// @Tags users
// @Accept json
// @Produce json
// @Param id path int true "ID do usuário"
// @Param request body models.CreateUserRequest true "Dados a serem atualizados"
// @Success 200 {object} models.User "Usuário atualizado"
// @Failure 400 {object} map[string]string "Erro de validação"
// @Failure 404 {object} map[string]string "Usuário não encontrado"
// @Router /users/{id} [put]
// @Security Bearer
func UpdateUser(c *gin.Context) {
id, err := strconv.Atoi(c.Param("id"))
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "ID inválido"})
return
}
var req models.CreateUserRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
user := models.User{
ID: id,
Name: req.Name,
Email: req.Email,
Age: req.Age,
}
c.JSON(http.StatusOK, user)
}
// DeleteUser deleta um usuário
// @Summary Deletar usuário
// @Description Remove um usuário do sistema permanentemente
// @Tags users
// @Accept json
// @Produce json
// @Param id path int true "ID do usuário"
// @Success 204 ""
// @Failure 404 {object} map[string]string "Usuário não encontrado"
// @Router /users/{id} [delete]
// @Security Bearer
func DeleteUser(c *gin.Context) {
id, err := strconv.Atoi(c.Param("id"))
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "ID inválido"})
return
}
// Simulação: usuário deletado
c.JSON(http.StatusNoContent, nil)
}</code></pre>
<p>Cada anotação tem um propósito específico:</p>
<ul>
<li><code>@Summary</code> e <code>@Description</code>: explicam o que o endpoint faz</li>
<li><code>@Tags</code>: agrupam endpoints relacionados na interface</li>
<li><code>@Param</code>: documentam parâmetros (path, query, body)</li>
<li><code>@Success</code> e <code>@Failure</code>: documentam respostas possíveis com seus status codes e estruturas</li>
<li><code>@Router</code>: define o caminho e método HTTP</li>
<li><code>@Security</code>: indica que o endpoint requer autenticação</li>
</ul>
<h2>Gerando a Documentação e Acessando a Interface</h2>
<p>Após anotar seu código, execute o swaggo para gerar a especificação OpenAPI:</p>
<pre><code class="language-bash">swag init</code></pre>
<p>Esse comando procura por anotações em seu projeto (começando por <code>main.go</code> por padrão) e cria um diretório <code>docs/</code> com arquivos YAML e JSON que descrevem sua API. Você verá uma mensagem de sucesso indicando que o arquivo <code>swagger.yaml</code> foi gerado.</p>
<p>Agora execute sua aplicação:</p>
<pre><code class="language-bash">go run main.go</code></pre>
<p>Acesse <code>http://localhost:8080/swagger/index.html</code> em seu navegador. Você verá a interface Swagger UI — uma página interativa e bonita onde pode explorar todos os seus endpoints, ver seus parâmetros, testar requisições diretamente da interface, e visualizar respostas reais.</p>
<h3>Regenerando Documentação após Alterações</h3>
<p>Toda vez que você alterar anotações ou adicionar novos endpoints, execute <code>swag init</code> novamente. Para desenvolvimento contínuo, você pode instalar uma ferramenta como <code>air</code> para recompilar automaticamente:</p>
<pre><code class="language-bash">go install github.com/cosmtrek/air@latest
air</code></pre>
<p>Isso executará <code>swag init</code> a cada mudança nos arquivos, mantendo a documentação sempre sincronizada com seu código.</p>
<h2>Boas Práticas e Padrões Avançados</h2>
<h3>Versionamento de API</h3>
<p>É uma prática saudável versionamento de API. A rota <code>/api/v1</code> em nosso exemplo já segue esse padrão. Se você precisar fazer mudanças incompatíveis no futuro, pode manter <code>/api/v1</code> para clientes antigos e criar <code>/api/v2</code> com as novas mudanças, sem quebrar ninguém.</p>
<h3>Documentação de Respostas de Erro</h3>
<p>Sempre documente explicitamente quais erros um endpoint pode retornar. Isso ajuda consumidores a lidar com falhas corretamente:</p>
<pre><code class="language-go">// @Failure 400 {object} ErrorResponse "Erro de validação"
// @Failure 401 {object} ErrorResponse "Não autenticado"
// @Failure 403 {object} ErrorResponse "Sem permissão"
// @Failure 500 {object} ErrorResponse "Erro interno do servidor"</code></pre>
<p>Defina um tipo <code>ErrorResponse</code> claro em seus modelos:</p>
<pre><code class="language-go">type ErrorResponse struct {
Code int json:"code" example:"400"
Message string json:"message" example:"Email já existe"
Details string json:"details,omitempty" example:"O campo 'email' deve ser único"
}</code></pre>
<h3>Documentando Query Parameters e Headers</h3>
<p>Se seu endpoint aceita filtros ou parâmetros opcionais:</p>
<pre><code class="language-go">// @Param limit query int false "Número máximo de resultados" default(10)
// @Param offset query int false "Número de registros a pular" default(0)
// @Param sort query string false "Campo para ordenação" Enums(id,name,email)</code></pre>
<p>Para headers customizados:</p>
<pre><code class="language-go">// @Param X-Request-ID header string false "ID único da requisição"</code></pre>
<h3>Autenticação e Segurança</h3>
<p>Já mencionamos <code>@Security Bearer</code> nas anotações. Você pode definir múltiplos esquemas de segurança globalmente e aplicar a endpoints específicos:</p>
<pre><code class="language-go">// @securityDefinitions.apikey ApiKeyAuth
// @in header
// @name X-API-Key
// @securityDefinitions.basic BasicAuth</code></pre>
<p>Depois, em cada endpoint, especifique qual segurança se aplica:</p>
<pre><code class="language-go">// @Security ApiKeyAuth
// @Security BasicAuth</code></pre>
<h2>Conclusão</h2>
<p>A documentação de APIs é tão importante quanto o código que as implementa. O Swagger e swaggo resolvem o problema clássico de documentação desatualizada, permitindo que você mantenha a especificação viva no seu código-fonte. Primeiro aprendizado: <strong>anotações no código são manutenção zero de documentação</strong> — você muda o código, atualiza a anotação ali mesmo, executa <code>swag init</code>, e pronto.</p>
<p>Segundo ponto-chave: <strong>a interface Swagger UI transforma especificação técnica em experiência visual</strong>. Desenvolvedores podem explorar sua API interativamente, testar endpoints sem escrever curl, entender estruturas de dados rapidamente. Isso reduz drasticamente o tempo de onboarding e diminui bugs de integração causados por desentendimentos sobre a API.</p>
<p>Por fim, <strong>swaggo não adiciona overhead ao seu projeto</strong> — trata-se apenas de geração de arquivos estáticos (YAML/JSON), não de middleware ou complexidade em runtime. A documentação é gerada uma única vez durante desenvolvimento e pode ser servida estaticamente em produção, sem custo de performance.</p>
<h2>Referências</h2>
<ul>
<li><a href="https://swagger.io/specification/" target="_blank" rel="noopener noreferrer">Documentação Oficial do Swagger/OpenAPI</a></li>
<li><a href="https://github.com/swaggo/swag" target="_blank" rel="noopener noreferrer">Repositório swaggo no GitHub</a></li>
<li><a href="https://gin-gonic.com/docs/" target="_blank" rel="noopener noreferrer">Documentação Gin Framework</a></li>
<li><a href="https://spec.openapis.org/oas/v3.0.3" target="_blank" rel="noopener noreferrer">OpenAPI 3.0 Specification</a></li>
<li><a href="https://swagger.io/resources/articles/best-practices-in-api-documentation/" target="_blank" rel="noopener noreferrer">Best Practices for REST API Documentation</a></li>
</ul>
<p><!-- FIM --></p>