💻 Exemplos: Capítulo 04: Middlewares Customizados no Gin (Auth, Logger, Recovery, CORS)
Especialização em Backend com Go & Gin • Demonstrações Práticas Compiláveis
💻 Código de Exemplo 01 — Middleware de Logging com Medição de Latência
package main
import (
"log"
"time"
"github.com/gin-gonic/gin"
)
func LoggerComLatencia() gin.HandlerFunc {
return func(c *gin.Context) {
inicio := time.Now()
c.Next() // deixa o restante da cadeia (e o handler) executar
latencia := time.Since(inicio)
status := c.Writer.Status()
log.Printf("[GIN] %-6s %-30s %d (%s)", c.Request.Method, c.Request.URL.Path, status, latencia)
}
}
func main() {
engine := gin.New()
engine.Use(LoggerComLatencia(), gin.Recovery())
engine.GET("/lento", func(c *gin.Context) {
time.Sleep(120 * time.Millisecond)
c.JSON(200, gin.H{"mensagem": "processado"})
})
engine.Run(":8080")
}
💻 Código de Exemplo 02 — Recovery Customizado e CORS
package main
import (
"log"
"net/http"
"github.com/gin-gonic/gin"
)
func RecoveryComLog() gin.HandlerFunc {
return func(c *gin.Context) {
defer func() {
if err := recover(); err != nil {
log.Printf("PANIC RECUPERADO em %s: %v", c.Request.URL.Path, err)
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{
"erro": "ocorreu um erro inesperado, tente novamente mais tarde",
})
}
}()
c.Next()
}
}
func CORS() gin.HandlerFunc {
return func(c *gin.Context) {
c.Header("Access-Control-Allow-Origin", "*")
c.Header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
c.Header("Access-Control-Allow-Headers", "Content-Type, Authorization")
if c.Request.Method == http.MethodOptions {
c.AbortWithStatus(http.StatusNoContent)
return
}
c.Next()
}
}
func main() {
engine := gin.New()
engine.Use(CORS(), RecoveryComLog())
engine.GET("/instavel", func(c *gin.Context) {
var ponteiro *int
c.JSON(http.StatusOK, gin.H{"valor": *ponteiro}) // provoca nil pointer panic
})
engine.Run(":8080")
}
💻 Código de Exemplo 03 — Contexto Compartilhado e Cadeia com Abort Condicional
package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
func AutenticarPorChaveAPI() gin.HandlerFunc {
return func(c *gin.Context) {
chave := c.GetHeader("X-API-Key")
if chave != "chave-secreta-empresa" {
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"erro": "chave de API inválida"})
return
}
// Dados calculados aqui ficam disponíveis para todos os handlers
// subsequentes na mesma requisição.
c.Set("usuario_id", 1001)
c.Set("perfil", "ADMIN")
c.Next()
}
}
func PerfilHandler(c *gin.Context) {
usuarioID, existe := c.Get("usuario_id")
if !existe {
c.JSON(http.StatusInternalServerError, gin.H{"erro": "contexto de usuário ausente"})
return
}
perfil := c.MustGet("perfil")
c.JSON(http.StatusOK, gin.H{"id": usuarioID, "perfil": perfil})
}
func main() {
engine := gin.New()
engine.Use(gin.Recovery())
protegido := engine.Group("/api", AutenticarPorChaveAPI())
protegido.GET("/perfil", PerfilHandler)
engine.Run(":8080")
}