"Um API Gateway é a porta de entrada que protege, limita e observa todos os requests antes que cheguem aos microsserviços." — #30DiasJava Gateway Notes

🎯 Objetivo do Day 14

Com todos os serviços internos rodando, era hora de criar uma camada única de entrada. O Day 14 do #30DiasJava entregou um API Gateway completo com rate limiting inteligente, circuit breakers, transformação de requests/responses e observabilidade unificada.

🛠️ O que foi implementado

✅ API Gateway Centralizado

  • Spring Cloud Gateway: Gateway reativo com rotas dinâmicas
  • Route configuration: YAML ou código para definir rotas, predicates e filters
  • Request/Response transformation: Modificação de headers, body, path
  • Load balancing: Distribuição de carga entre instâncias do mesmo serviço
  • SSL/TLS termination: Terminação SSL no gateway

✅ Rate Limiting Avançado

  • Token bucket algorithm: Implementação Redis-based para rate limiting distribuído
  • Limits por usuário: Limites personalizados por userId (ex.: premium: 1000/min, free: 100/min)
  • Limits por tenant: Limites por organização/tenant
  • Limits por endpoint: Limites específicos por rota (ex.: /api/auth/login: 5/min)
  • Headers HTTP: X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset

✅ Circuit Breakers

  • Resilience4j integration: Circuit breakers automáticos para rotas
  • Fallback responses: Respostas padrão quando serviços estão down
  • Retry policies: Retry com backoff exponencial
  • Bulkhead isolation: Isolamento de recursos por rota

✅ Segurança e Autenticação

  • JWT validation: Validação centralizada de tokens no gateway
  • API key authentication: Suporte a API keys para integrações
  • IP whitelisting/blacklisting: Controle de acesso por IP
  • CORS policy: Configuração centralizada de CORS
  • Request size limits: Limites de tamanho de request

✅ Observabilidade

  • Metrics por rota: Taxa de requests, latência, taxa de erro por rota
  • Tracing distribuído: Correlation ID propagado automaticamente
  • Access logs estruturados: Logs JSON com contexto rico
  • Dashboard Grafana: Visão unificada de todas as rotas

📊 Arquitetura

┌─────────────┐
│   Client    │
└──────┬──────┘
       │
       ▼
┌─────────────────────────────────────┐
│         API Gateway                 │
│  ┌──────────────────────────────┐  │
│  │ Rate Limiting (Redis)        │  │
│  ├──────────────────────────────┤  │
│  │ JWT Validation               │  │
│  ├──────────────────────────────┤  │
│  │ Circuit Breaker (Resilience4j)│ │
│  ├──────────────────────────────┤  │
│  │ Request Transformation       │  │
│  └──────────────────────────────┘  │
└──────┬──────────────────────────────┘
       │
       ├──────────────┬──────────────┐
       ▼              ▼              ▼
┌──────────┐   ┌──────────┐   ┌──────────┐
│ Backend  │   │ Payment  │   │ Search   │
│ Service  │   │ Service  │   │ Service  │
└──────────┘   └──────────┘   └──────────┘

🔧 Implementação Técnica

1. Dependências (pom.xml)

<!-- Spring Cloud Gateway -->
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

<!-- Rate Limiting -->
<dependency>
  <groupId>com.github.vladimir-bukhtoyarov</groupId>
  <artifactId>bucket4j-core</artifactId>
  <version>8.10.0</version>
</dependency>

<!-- Resilience4j -->
<dependency>
  <groupId>io.github.resilience4j</groupId>
  <artifactId>resilience4j-spring-boot3</artifactId>
</dependency>

<!-- Redis for distributed rate limiting -->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>

2. Gateway Routes Configuration

spring:
  cloud:
    gateway:
      routes:
        - id: backend-service
          uri: lb://backend-service
          predicates:
            - Path=/api/**
          filters:
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 100
                redis-rate-limiter.burstCapacity: 200
                key-resolver: "#{@userKeyResolver}"
            - name: CircuitBreaker
              args:
                name: backendCircuitBreaker
                fallbackUri: forward:/fallback
            - StripPrefix=1
        
        - id: auth-service
          uri: lb://auth-service
          predicates:
            - Path=/auth/**
          filters:
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 10
                redis-rate-limiter.burstCapacity: 20
                key-resolver: "#{@ipKeyResolver}"

3. Custom Rate Limiter

@Component
public class UserRateLimiter implements KeyResolver {
  @Override
  public Mono<String> resolve(ServerWebExchange exchange) {
    String userId = extractUserId(exchange);
    if (userId != null) {
      return Mono.just(userId);
    }
    return Mono.just("anonymous:" + getClientIP(exchange));
  }
}

💡 Lições do dia

  • Rate limiting é essencial: Protege contra abuso e garante fair usage
  • Circuit breakers previnem cascading failures: Isolam falhas antes que se espalhem
  • Gateway centraliza cross-cutting concerns: Autenticação, rate limiting, observabilidade em um só lugar
  • Redis é crucial: Rate limiting distribuído requer estado compartilhado
  • Fallbacks melhoram UX: Respostas padrão quando serviços estão down

📈 Métricas e Observabilidade

  • gateway.requests.total{route, status}: Total de requests por rota
  • gateway.latency.seconds{route, percentile}: Latência por rota
  • gateway.rate_limited.total{route}: Requests bloqueados por rate limit
  • gateway.circuit_breaker.state{route}: Estado do circuit breaker

🔗 Recursos


Next episodeDay 15/30 — Caching Strategies in Spring Boot