Backend for frontend (BFF)
Give each client one endpoint that fans out, so a phone is not making six calls.
Open this lesson in the learning hubKey points
- A BFF is a thin service owned by one client team. The mobile BFF can change shape without the web BFF or the domain services moving.
- It composes: one request in, several calls out in parallel, one response shaped exactly for the screen that asked.
- What it saves is round trips, which is what hurts on a mobile network. Six sequential calls at 120 ms each is a visibly slow screen.
- Give every fan-out call its own timeout and fallback. A missing promotions block should hide that block, not fail the page.
- Keep it dumb. Business rules belong in the service that owns the data, or the BFF quietly grows into a second monolith.
Example
@RestController
class HomeBff {
private final Orders orders;
private final Profiles profiles;
private final Promotions promotions;
private final Executor pool; // virtual threads suit this well
@GetMapping("/mobile/home")
HomeView home(@AuthenticationPrincipal Jwt user) {
String id = user.getSubject();
// Three calls at once, not one after another.
var ordersF = CompletableFuture.supplyAsync(() -> orders.recent(id), pool);
var profileF = CompletableFuture.supplyAsync(() -> profiles.get(id), pool);
// Promotions are optional: late or broken means hide the block.
var promosF = CompletableFuture.supplyAsync(() -> promotions.forUser(id), pool)
.completeOnTimeout(List.of(), 200, TimeUnit.MILLISECONDS)
.exceptionally(failure -> List.of());
return new HomeView(ordersF.join(), profileF.join(), promosF.join());
}
}
One call per screen, composed on the server, with the optional parts allowed to fail.
This is a reading copy. The full lesson — with the visual explainer, the interactive lab and a Run button for the code — lives in the Microservices course, and every lesson in it is listed on the Microservices contents page.