7.3 API Gateway with Spring Cloud Gateway
← Back to Chapter 7: Microservices & Spring Cloud
An API Gateway acts as the single public entry point for all client requests. It shields internal microservice topography, offloads cross-cutting edge concerns (authentication, rate limiting, CORS), and routes traffic dynamically.
1. Gateway Architecture & Core Concepts
Built natively on Project Reactor and Netty (non-blocking, reactive runtime), Spring Cloud Gateway provides superior throughput compared to legacy blocking reverse proxies.
[ Mobile / Web Clients ]
│ https://api.codewithsarvy.dev
▼
┌─────────────────────────────────────────────────────────────┐
│ Spring Cloud Gateway │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Route: ID, Destination URI, Predicates, Filters │ │
│ ├─────────────────────────────────────────────────────────┤ │
│ │ Predicates: Path=/api/orders/**, Header=X-Client-Type │ │
│ ├─────────────────────────────────────────────────────────┤ │
│ │ Gateway Filters: AddRequestHeader, RateLimiter, Token │ │
│ └─────────────────────────────────────────────────────────┘ │
└──────────────┬───────────────────────────┬──────────────────┘
│ lb://order-service │ lb://payment-service
▼ ▼
[ Order Service Pods ] [ Payment Service Pods ]
2. Declarative Route Configuration (application.yml)
spring:
cloud:
gateway:
discovery:
locator:
enabled: true # Automatically route using Eureka service names
routes:
- id: order-service-route
uri: lb://order-service # Dynamic client-side load balanced URI!
predicates:
- Path=/api/v1/orders/**
filters:
- AddRequestHeader=X-Gateway-Source, CodeWithSarvyGateway
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 10
redis-rate-limiter.burstCapacity: 20
- id: payment-service-route
uri: lb://payment-service
predicates:
- Path=/api/v1/payments/**
3. Custom Global Authentication Gateway Filter
Authenticate JWT tokens at the gateway boundary so invalid requests are rejected before ever reaching internal microservice clusters:
@Component
public class AuthenticationGatewayFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
if (isSecured(request)) {
if (!request.getHeaders().containsKey(HttpHeaders.AUTHORIZATION)) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
String token = request.getHeaders().getFirst(HttpHeaders.AUTHORIZATION);
if (!isValidJwt(token)) {
exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
return exchange.getResponse().setComplete();
}
}
return chain.filter(exchange);
}
@Override
public int getOrder() { return -1; } // High precedence
}