APiGen BFF (Backend For Frontend) Module
A Spring Boot module that provides Backend For Frontend (BFF) capabilities with query composition, client-specific response tailoring, and combined rate limiting.
Overview
The BFF pattern solves common challenges in microservice architectures:
- Query Composition: Aggregate multiple microservice calls into single responses
- Response Tailoring: Customize responses per client type (mobile/web/desktop/IoT/API)
- Combined Rate Limiting: Apply rate limits across aggregated services
- Reduced Round Trips: Optimize frontend requests and improve performance
Features
1. Query Composition
Compose multiple microservice calls with different strategies:
- Parallel All: Execute all requests in parallel, fail if any fails
- Parallel Best-Effort: Execute in parallel, return partial results on failure
- Sequential: Execute one-by-one, stop on first failure
- Sequential Best-Effort: Execute sequentially, continue on failure
2. Response Tailoring
Automatically optimize responses based on client capabilities:
- Mobile: Excludes audit fields (createdAt, updatedAt, metadata) for smaller payloads
- Web: Balanced payloads with full feature set
- Desktop: Larger payloads with detailed information
- IoT: Minimal payloads, essential data only
- API: Full raw data without optimizations
3. Combined Rate Limiting
Smart rate limiting that considers the cost of aggregated requests:
- Request weight based on number of services (3 services = 3x weight)
- Sliding window algorithm for fair distribution
- Per-endpoint and per-user tracking
- Configurable limits and windows
Quick Start
1. Enable BFF Auto-Configuration
yaml
apigen:
bff:
enabled: true
default-rate-limit: 60
default-timeout-ms: 5000
response-tailoring:
enabled: true2. Create a BFF Endpoint
java
@RestController
@RequestMapping("/api/bff")
public class ProductBffController {
private final QueryCompositionService compositionService;
@GetMapping("/product/{id}")
@BffEndpoint(
services = {"products", "reviews", "inventory"},
strategy = CompositionStrategy.PARALLEL_ALL,
supportedClients = {ClientType.MOBILE, ClientType.WEB}
)
public Mono<Map<String, Object>> getProductDetails(@PathVariable Long id) {
List<ServiceRequest> requests = List.of(
ServiceRequest.builder().serviceId("products").path("/api/products/" + id).build(),
ServiceRequest.builder().serviceId("reviews").path("/api/reviews/product/" + id).build(),
ServiceRequest.builder().serviceId("inventory").path("/api/inventory/product/" + id).build()
);
return compositionService.compose(requests, CompositionStrategy.PARALLEL_ALL);
}
}Client Type Headers
Specify the client type using the X-Client-Type header:
bash
# Mobile client
curl -H "X-Client-Type: MOBILE" http://localhost:8080/api/bff/endpoint
# Web client
curl -H "X-Client-Type: WEB" http://localhost:8080/api/bff/endpoint