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")
}