Spec Backend Com Golang E Gin • Trilha Progressiva em 4 Níveis


🎯 Nível 1: Fundamentos

Problema 04.1 — Middleware de Logging com c.Next() e Duração da Requisição

Contexto: Middleware de Logging com c.Next() e Duração da Requisição no contexto de Middlewares Customizados no Gin.

Requisitos de Execução:

  1. Implementar middleware que calcule o tempo de execução e imprima método, path e status.

Resultado Esperado

Log: [GIN] GET /api/v1/users 200 (1.24ms)

📤 Instruções de Entrega (Microsoft Teams)

  1. Salve o arquivo como: Atividade_04_1_SeuNome
  2. Envie na tarefa: Atividade Cap 04 - Middlewares Customizados no Gin
🔑 Gabarito de Código & Solução Comentada
// logger_middleware.go
package main

import (
	"log"
	"time"
	"github.com/gin-gonic/gin"
)

func CustomLogger() gin.HandlerFunc {
	return func(c *gin.Context) {
		t := time.Now()
		c.Next()
		latency := time.Since(t)
		status := c.Writer.Status()
		log.Printf("[GIN] %s %s %d (%s)", c.Request.Method, c.Request.URL.Path, status, latency)
	}
}

🔍 Nível 2: Prática

Problema 04.2 — Middleware de Recuperação contra Panic (Crash Recovery)

Contexto: Middleware de Recuperação contra Panic (Crash Recovery) no contexto de Middlewares Customizados no Gin.

Requisitos de Execução:

  1. Implementar middleware que intercepte panics na goroutine do handler e retorne 500 JSON sem derrubar o processo.

Resultado Esperado

Panic interceptado com sucesso -> Resposta 500 Internal Server Error enviada.

📤 Instruções de Entrega (Microsoft Teams)

  1. Salve o arquivo como: Atividade_04_2_SeuNome
  2. Envie na tarefa: Atividade Cap 04 - Middlewares Customizados no Gin
🔑 Gabarito de Código & Solução Comentada
// recovery_middleware.go
package main

import (
	"log"
	"net/http"
	"github.com/gin-gonic/gin"
)

func SafeRecovery() gin.HandlerFunc {
	return func(c *gin.Context) {
		defer func() {
			if err := recover(); err != nil {
				log.Printf("PANIC RECUPERADO: %v", err)
				c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"error": "Erro interno do servidor"})
			}
		}()
		c.Next()
	}
}

⚡ Nível 3: Integração

Problema 04.3 — Injeção e Extração de Valores no Contexto com c.Set() e c.Get()

Contexto: Injeção e Extração de Valores no Contexto com c.Set() e c.Get() no contexto de Middlewares Customizados no Gin.

Requisitos de Execução:

  1. Gravar informações de tenant ou usuário no contexto no middleware e recuperá-las tipadas no handler final.

Resultado Esperado

Usuário autenticado no middleware recuperado no handler de perfil.

📤 Instruções de Entrega (Microsoft Teams)

  1. Salve o arquivo como: Atividade_04_3_SeuNome
  2. Envie na tarefa: Atividade Cap 04 - Middlewares Customizados no Gin
🔑 Gabarito de Código & Solução Comentada
// context_store.go
package main

import (
	"net/http"
	"github.com/gin-gonic/gin"
)

func AuthContextMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		c.Set("usuario_id", 1001)
		c.Set("perfil", "ADMIN")
		c.Next()
	}
}

func PerfilHandler(c *gin.Context) {
	userId, _ := c.Get("usuario_id")
	c.JSON(http.StatusOK, gin.H{"id": userId})
}

🏆 Nível 4: Desafio Corporativo

Problema 04.4 — Cadeia de Middlewares com Abort Condicional e Métricas Prometheus

Contexto: Cadeia de Middlewares com Abort Condicional e Métricas Prometheus no contexto de Middlewares Customizados no Gin.

Requisitos de Execução:

  1. Montar pipeline de middlewares com interrupção rápida via c.AbortWithStatusJSON se header de segurança estiver ausente.

Resultado Esperado

Requisição bloqueada antecipadamente no primeiro middleware de segurança.

📤 Instruções de Entrega (Microsoft Teams)

  1. Salve o arquivo como: Atividade_04_4_SeuNome
  2. Envie na tarefa: Atividade Cap 04 - Middlewares Customizados no Gin
🔑 Gabarito de Código & Solução Comentada
// chain_abort.go
package main

import (
	"net/http"
	"github.com/gin-gonic/gin"
)

func ExigirChaveApi() gin.HandlerFunc {
	return func(c *gin.Context) {
		key := c.GetHeader("X-API-Key")
		if key != "chave_secreta_empresa" {
			c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"erro": "Chave de API inválida"})
			return
		}
		c.Next()
	}
}