"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 rotagateway.latency.seconds{route, percentile}: Latência por rotagateway.rate_limited.total{route}: Requests bloqueados por rate limitgateway.circuit_breaker.state{route}: Estado do circuit breaker
🔗 Recursos
- Repositório: https://github.com/adelmonsouza/30DiasJava-Day14-APIGateway
- Spring Cloud Gateway: https://spring.io/projects/spring-cloud-gateway
- Bucket4j: https://bucket4j.com/
- Resilience4j: https://resilience4j.readme.io/
- Projeto pessoal: Este é um projeto do desafio #30DiasJava, mantido independentemente para fins educacionais.
Next episode → Day 15/30 — Caching Strategies in Spring Boot