Especialização em Backend com Go & Gin • Demonstrações Práticas Compiláveis


💻 Código de Exemplo 01 — Handlers Anotados com Swag (CRUD de Pedidos)

package handlers

import (
	"net/http"
	"strconv"

	"github.com/gin-gonic/gin"
)

// PedidoResponse representa o schema de resposta documentado no Swagger.
type PedidoResponse struct {
	ID     int     `json:"id" example:"42"`
	Status string  `json:"status" example:"processando"`
	Valor  float64 `json:"valor" example:"199.90"`
}

// ErroResponse é o schema padrão de erro usado em todas as rotas @Failure.
type ErroResponse struct {
	Mensagem string `json:"mensagem" example:"pedido não encontrado"`
}

// ObterPedido godoc
// @Summary      Obter pedido por ID
// @Description  Retorna os detalhes de um pedido específico
// @Tags         Pedidos
// @Produce      json
// @Param        id   path      int  true  "ID do pedido"
// @Success      200  {object}  PedidoResponse
// @Failure      404  {object}  ErroResponse
// @Security     BearerAuth
// @Router       /pedidos/{id} [get]
func ObterPedido(c *gin.Context) {
	id, err := strconv.Atoi(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, ErroResponse{Mensagem: "id inválido"})
		return
	}
	if id != 42 {
		c.JSON(http.StatusNotFound, ErroResponse{Mensagem: "pedido não encontrado"})
		return
	}
	c.JSON(http.StatusOK, PedidoResponse{ID: id, Status: "processando", Valor: 199.90})
}

// CriarPedidoRequest é o corpo esperado para criação de pedido.
type CriarPedidoRequest struct {
	ClienteID int     `json:"cliente_id" binding:"required" example:"7"`
	Valor     float64 `json:"valor" binding:"required,gt=0" example:"150.00"`
}

// CriarPedido godoc
// @Summary      Criar novo pedido
// @Description  Cria um pedido a partir do corpo JSON informado
// @Tags         Pedidos
// @Accept       json
// @Produce      json
// @Param        pedido  body      CriarPedidoRequest  true  "Dados do pedido"
// @Success      201     {object}  PedidoResponse
// @Failure      400     {object}  ErroResponse
// @Security     BearerAuth
// @Router       /pedidos [post]
func CriarPedido(c *gin.Context) {
	var req CriarPedidoRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, ErroResponse{Mensagem: err.Error()})
		return
	}
	c.JSON(http.StatusCreated, PedidoResponse{ID: 99, Status: "criado", Valor: req.Valor})
}

💻 Código de Exemplo 02 — main.go com Security Definitions e Registro do Swagger UI

package main

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

	_ "meuservico/docs" // gerado por `swag init`; registra a spec via init()
	"meuservico/handlers"
)

// @title           API de Pedidos
// @version         1.0
// @description     Serviço de gerenciamento de pedidos com autenticação JWT.
// @host            localhost:8080
// @BasePath        /api/v1

// @securityDefinitions.apikey  BearerAuth
// @in                          header
// @name                        Authorization
// @description                 Informe: Bearer {seu_token_jwt}
func main() {
	r := gin.Default()

	r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))

	v1 := r.Group("/api/v1")
	{
		v1.GET("/pedidos/:id", handlers.ObterPedido)
		v1.POST("/pedidos", handlers.CriarPedido)
	}

	r.Run(":8080")
}

// Fluxo de geração:
//   1. go install github.com/swaggo/swag/cmd/swag@latest
//   2. swag init                     -> gera docs/docs.go, docs/swagger.json, docs/swagger.yaml
//   3. go run main.go
//   4. abrir http://localhost:8080/swagger/index.html

💻 Código de Exemplo 03 — Validação de Sincronia da Documentação em CI

// check_swagger_sync.go
package main

import (
	"bytes"
	"log"
	"os/exec"
)

// VerificarSwaggerSincronizado roda `swag init` de novo e compara a saída
// com o que está commitado em docs/. Usado como etapa de pipeline CI —
// se houver diff, alguém alterou rotas/DTOs sem regenerar a documentação.
func VerificarSwaggerSincronizado() error {
	cmd := exec.Command("swag", "init", "--output", "docs")
	if out, err := cmd.CombinedOutput(); err != nil {
		return err
	}

	diff := exec.Command("git", "diff", "--exit-code", "docs/")
	var stderr bytes.Buffer
	diff.Stderr = &stderr
	if err := diff.Run(); err != nil {
		log.Println("documentação Swagger desatualizada:", stderr.String())
		return err
	}

	log.Println("documentação Swagger 100% sincronizada com o código.")
	return nil
}