Go: Projeto Integrado: API de comércio eletrônico (Parte 3)
Última atualização: 2026-08-26
Temos a arquitetura, temos a segurança — agora, vamos colocá-la em operação.
Da primeira linha de código até a fase de produção: documentação Swagger, desligamento gradual, implantação no Docker, ajuste do pprof e monitoramento com o Prometheus. A API de comércio eletrônico do Bob está pronta para receber usuários reais.
1. Você aprenderá
- Geração automática de documentação para Swagger / OpenAPI
server.ShutdownDesligamento controlado- Compilação em múltiplas etapas do Docker + Docker Compose full stack
- Integração do pprof para análise de desempenho em endpoints
- Exposição das métricas do Prometheus
- Definição dos parâmetros de avaliação dos exames de saúde
2. História: A noite antes do lançamento
(1) Pontos críticos: falta de documentação, falta de monitoramento e implantação manual
A API de comércio eletrônico do Bob está totalmente funcional, mas a equipe de operações se recusou a aceitá-la:
“A equipe de operações disse: ‘Sem documentação da API, o front-end não consegue se integrar a ela. Sem verificações de integridade, não sabemos se o serviço está funcionando. Sem monitoramento, nem saberíamos se ele tivesse parado de funcionar. E ainda precisamos transferir manualmente os binários via SCP para a implantação — isso é muito primitivo.’”
Lista de verificação para o lançamento:
❌ API docs → Frontend has to ask "what fields does this endpoint return?" every time
❌ Graceful shutdown → Kill process causes in-flight orders to be lost
❌ Docker deploy → SCP binary to server, start manually
❌ Performance monitoring → Don't know which part of the API is slow
(2) Objetivo da aula: Pronto para produção
✅ Swagger docs → Frontend self-service browsing
✅ Graceful Shutdown → Signal handling + wait for connections to close
✅ Docker Compose → One command to start the full stack
✅ pprof + Prometheus → Performance visualization
3. Implementação completa
(1) ▶ Exemplo: Desligamento controlado
⚙️ Pré-requisito: Execute
go get github.com/mattn/go-sqlite3(requer CGO; como alternativa, usemodernc.org/sqlitepara um driver exclusivamente de Go)
// cmd/server/main.go
package main
import (
"context"
"database/sql"
"encoding/json"
"log"
"net/http"
"os"
"os/signal"
"syscall"
"time"
"ecommerce/internal/handler"
"ecommerce/internal/repository"
"ecommerce/internal/service"
_ "github.com/mattn/go-sqlite3"
)
func main() {
db, err := sql.Open("sqlite3", "./ecommerce.db")
if err != nil {
log.Fatal(err)
}
defer db.Close()
db.SetMaxOpenConns(25)
db.SetMaxIdleConns(10)
db.SetConnMaxLifetime(5 * time.Minute)
// Dependency injection
userRepo := repository.NewUserRepository(db)
productRepo := repository.NewProductRepository(db)
orderRepo := repository.NewOrderRepository(db)
userSvc := service.NewUserService(userRepo)
productSvc := service.NewProductService(productRepo)
orderSvc := service.NewOrderService(orderRepo, productRepo, userRepo)
userHandler := handler.NewUserHandler(userSvc)
productHandler := handler.NewProductHandler(productSvc)
orderHandler := handler.NewOrderHandler(orderSvc)
mux := http.NewServeMux()
userHandler.Register(mux)
productHandler.Register(mux)
orderHandler.Register(mux)
// Health check endpoint
mux.HandleFunc("GET /health", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]string{"status": "ok"})
})
mux.HandleFunc("GET /ready", func(w http.ResponseWriter, r *http.Request) {
if err := db.Ping(); err != nil {
w.WriteHeader(http.StatusServiceUnavailable)
json.NewEncoder(w).Encode(map[string]string{"status": "not ready"})
return
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]string{"status": "ready"})
})
server := &http.Server{
Addr: ":8080",
Handler: mux,
// Timeout settings (prevent slowloris attacks)
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
IdleTimeout: 60 * time.Second,
ReadHeaderTimeout: 5 * time.Second,
}
// Graceful Shutdown
go func() {
sigCh := make(chan os.Signal, 1)
signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
sig := <-sigCh
log.Printf("Received signal %v, shutting down...", sig)
// Give in-flight requests up to 30 seconds to complete
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
if err := server.Shutdown(ctx); err != nil {
log.Printf("Forced shutdown: %v", err)
}
}()
log.Println("E-commerce API listening on :8080")
if err := server.ListenAndServe(); err != http.ErrServerClosed {
log.Fatal(err)
}
log.Println("Server shut down safely")
}
(2) ▶ Exemplo: Integração do pprof com o Prometheus
⚙️ Pré-requisito: Executar
go get github.com/prometheus/client_golang/prometheusego get github.com/prometheus/client_golang/prometheus/promhttp
// monitoring.go
package main
import (
"net/http"
"net/http/pprof"
"runtime"
"strconv"
"time"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
// Prometheus metrics
var (
httpRequestsTotal = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "http_requests_total",
Help: "Total HTTP requests",
},
[]string{"method", "path", "status"},
)
httpRequestDuration = prometheus.NewHistogramVec(
prometheus.HistogramOpts{
Name: "http_request_duration_seconds",
Help: "HTTP request duration in seconds",
Buckets: []float64{.001, .005, .01, .025, .05, .1, .25, .5, 1, 2.5, 5},
},
[]string{"method", "path"},
)
activeGoroutines = prometheus.NewGaugeFunc(
prometheus.GaugeOpts{
Name: "go_goroutines_active",
Help: "Current number of goroutines",
},
func() float64 {
return float64(runtime.NumGoroutine())
},
)
)
func init() {
prometheus.MustRegister(httpRequestsTotal)
prometheus.MustRegister(httpRequestDuration)
prometheus.MustRegister(activeGoroutines)
}
// Prometheus middleware
func prometheusMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
// Wrap ResponseWriter to get status code
wrapped := &responseWriter{ResponseWriter: w, statusCode: http.StatusOK}
next.ServeHTTP(wrapped, r)
duration := time.Since(start)
httpRequestsTotal.WithLabelValues(
r.Method, r.URL.Path, strconv.Itoa(wrapped.statusCode),
).Inc()
httpRequestDuration.WithLabelValues(
r.Method, r.URL.Path,
).Observe(duration.Seconds())
})
}
type responseWriter struct {
http.ResponseWriter
statusCode int
}
func (rw *responseWriter) WriteHeader(code int) {
rw.statusCode = code
rw.ResponseWriter.WriteHeader(code)
}
// Register pprof and Prometheus endpoints in main
func registerMonitoring(mux *http.ServeMux) {
// pprof endpoints
mux.HandleFunc("/debug/pprof/", pprof.Index)
mux.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
mux.HandleFunc("/debug/pprof/profile", pprof.Profile)
mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
mux.HandleFunc("/debug/pprof/trace", pprof.Trace)
// Prometheus metrics
mux.Handle("/metrics", promhttp.Handler())
}
func main() {
mux := http.NewServeMux()
registerMonitoring(mux)
// Example business endpoint
mux.HandleFunc("GET /api/products", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte(`{"products":[]}`))
})
// Health check
mux.HandleFunc("GET /health", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte(`{"status":"ok"}`))
})
log.Println("Monitoring + API server listening on :8080")
http.ListenAndServe(":8080", prometheusMiddleware(mux))
}
(3) ▶ Exemplo: Implantação do Docker
# Dockerfile (Multi-stage Build)
FROM golang:1.22-alpine AS builder
WORKDIR /app
# Dependency cache
COPY go.mod go.sum ./
RUN go mod download
# Source + compile
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o /app/server ./cmd/server
# === Run stage ===
FROM alpine:3.19
RUN apk --no-cache add ca-certificates tzdata
COPY --from=builder /app/server /server
EXPOSE 8080
EXPOSE 6060 # pprof
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD wget -qO- http://localhost:8080/health || exit 1
CMD ["/server"]
# docker-compose.yml
version: '3.8'
services:
api:
build: .
ports:
- "8080:8080"
- "6060:6060" # pprof
environment:
- DB_PATH=/data/ecommerce.db
- GIN_MODE=release
volumes:
- data:/data
restart: unless-stopped
healthcheck:
test: ["CMD", "wget", "-qO-", "http://localhost:8080/health"]
interval: 30s
timeout: 3s
retries: 3
start_period: 5s
prometheus:
image: prom/prometheus:latest
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
- prometheus_data:/prometheus
grafana:
image: grafana/grafana:latest
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
volumes:
- grafana_data:/var/lib/grafana
volumes:
data:
prometheus_data:
grafana_data:
# prometheus.yml
global:
scrape_interval: 15s
scrape_configs:
- job_name: 'ecommerce-api'
static_configs:
- targets: ['api:8080']
metrics_path: '/metrics'
(4) ▶ Exemplo: Documentação do Swagger
// Generate OpenAPI docs from comments (use with swag tool)
// Package handler handles HTTP requests.
//
// E-commerce API
//
// Schemes: http
// Host: localhost:8080
// BasePath: /api/v1
// Version: 1.0.0
//
// Consumes:
// - application/json
//
// Produces:
// - application/json
//
// swagger:meta
package handler
import "ecommerce/pkg/model"
// User information
// swagger:model
type User struct {
ID int `json:"id"`
Email string `json:"email"`
Name string `json:"name"`
}
// RegisterUser registers a new user
// swagger:route POST /api/v1/register users registerUser
//
// Register a new user
//
// Consumes:
// - application/json
//
// Produces:
// - application/json
//
// Responses:
// 201: User
// 400: ErrorResponse
// 409: ErrorResponse
func (h *UserHandler) RegisterUser(w http.ResponseWriter, r *http.Request) {
// handler logic
}
// swagger:parameters registerUser
type RegisterUserParams struct {
// in: body
Body model.RegisterRequest
}
// ErrorResponse error response
// swagger:response
type ErrorResponse struct {
// in: body
Body struct {
Error string `json:"error"`
}
}
# Install swag CLI
$ go install github.com/swaggo/swag/cmd/swag@latest
# Generate docs
$ swag init -g cmd/server/main.go
# Access docs
# http://localhost:8080/swagger/index.html
(5) Lista de verificação para o lançamento
✅ Graceful Shutdown — wait for requests to complete after kill
✅ Health Check — /health and /ready endpoints
✅ pprof — /debug/pprof/ performance analysis
✅ Prometheus — /metrics endpoint exposed
✅ Swagger — Auto-generated API documentation
✅ Docker — Multi-stage build, image < 20 MB
✅ docker-compose — One command to start the full stack
✅ ReadTimeout / WriteTimeout — prevent slowloris attacks
✅ DB connection pool — MaxOpenConns=25, MaxIdleConns=10
✅ server.Shutdown — SIGINT/SIGTERM handling
❓ Perguntas Frequentes
P: Por que o desligamento gradual é importante? R: Quando um sinal SIGTERM é recebido (como quando o Kubernetes encerra um Pod), o
server.Shutdownaguarda a conclusão de todas as solicitações HTTP ativas (até o tempo limite especificado) antes de fechar o listener. Se o processo for encerrado imediatamente, as solicitações que estão sendo processadas no momento serão interrompidas — resultando em dados de pedidos com ordem inconsistente.
P: Quais são as configurações de tempo limite do servidor? R: (1) ReadTimeout: tempo limite para a leitura de toda a solicitação (incluindo o corpo); (2) WriteTimeout: tempo limite para o envio de uma resposta; (3) IdleTimeout: tempo limite de inatividade para conexões Keep-Alive; (4) ReadHeaderTimeout: tempo limite para a leitura dos cabeçalhos da solicitação. Recomenda-se configurar todas essas opções para evitar ataques de conexão lenta.
P: O pprof é seguro em um ambiente de produção? R: O endpoint do pprof não deve ser exposto ao mundo externo. Solução: (1) Hospede-o em uma porta interna (por exemplo, :6060) que não seja compartilhada com as portas de negócios; (2) Proteja o caminho
/debug/pprof/com middleware de autenticação; (3) Habilite-o apenas no ambiente de teste. No ambiente de produção, recomenda-se habilitar a criação de perfis temporariamente, somente quando necessário.
P: Como faço para expor métricas do Prometheus? R: Use
promhttp.Handler()para expor métricas no endpoint/metrics. O servidor do Prometheus faz o scraping desse endpoint periodicamente. O Grafana se conecta à fonte de dados do Prometheus e cria visualizações. Métricas padrão: número de solicitações, distribuição de latência, taxa de erros, número de goroutines e número de eventos de GC.
P: Como faço para gerar automaticamente a documentação OpenAPI? R: Use a ferramenta
swaggo/swag— escreva comentários em um formato específico dentro do código do seu handler e, em seguida, executeswag initpara gerar o diretóriodocs/. Useswaggo/http-swaggerpara montar a documentação no endpoint/swagger/. Formato dos comentários:// swagger:route,// swagger:model,// swagger:parameters.
P: Como orquestrar vários serviços com o Docker Compose? R: Defina vários serviços (API, Prometheus, Grafana), use
depends_onpara controlar a ordem de inicialização e usevolumespara persistir os dados. Executedocker-compose up -dpara iniciar todos os serviços com um único comando. Em um ambiente de produção, use o Docker Stack ou o Kubernetes.
P: Existem três níveis de granularidade para as verificações de integridade? R: (1) /health (ativo) — A verificação mais simples; uma resposta 200 indica que o processo está em execução; (2) /ready (pronto) — Verifica se as dependências (banco de dados, cache) estão acessíveis; (3) /status (detalhado) — retorna o status e a latência de todas as dependências.
📖 Resumo
- Desligamento controlado:
server.Shutdown(ctx)+signal.Notify - Configurações de tempo limite: ReadTimeout / WriteTimeout / IdleTimeout
- pprof: endpoint
/debug/pprof/(não exposto externamente) - Prometheus: endpoint
/metrics+ métricas personalizadas - Swagger:
swaggo/swaggera OpenAPI a partir de comentários - Docker: Compilação em várias etapas + HEALTHCHECK
- Docker Compose: API + Prometheus + Grafana
- Verificações de integridade:
/health(ativo) +/ready(pronto)
📝 Exercícios
-
Básico (Dificuldade ⭐): Adicione configurações de desligamento gradual e de tempo limite à API de comércio eletrônico abordada nesta lição. Use
curlpara testar os endpoints/healthe/ready. Usekill -SIGTERM <pid>para testar o desligamento gradual. -
Avançado (Dificuldade ⭐⭐): Implemente uma implantação completa baseada em Docker. Requisitos: (1) Dockerfile com compilação em múltiplas etapas; (2) docker-compose.yml (API + Prometheus + Grafana); (3) HEALTHCHECK; (4) endpoint pprof (somente porta interna); (5) Verifique se todos os serviços iniciam normalmente após a execução de
docker-compose up. -
Desafio (Dificuldade ⭐⭐⭐): Implementar o monitoramento do Prometheus + painéis do Grafana. Requisitos: (1) Adicionar o middleware do Prometheus à API (contagem de solicitações, latência, taxa de erros); (2) Adicionar métricas de negócios (por exemplo, número de pedidos criados, número de usuários registrados); (3) Incluir o Prometheus e o Grafana no arquivo do Docker Compose; (4) Importar ou criar um painel do Grafana para exibir QPS, latência P99, taxa de erros e número de goroutines; (5) Verificar se as métricas estão corretas usando o Grafana após o teste de carga.
🎉 Parabéns! Você concluiu todas as 30 lições do tutorial de Go! Desde o “Hello World” até uma API de comércio eletrônico pronta para produção, você dominou todo o conjunto de habilidades necessárias para o desenvolvimento de back-end em Go.