mirror of
https://github.com/tiennm99/java-design-patterns.git
synced 2026-10-05 22:14:37 +00:00
* Add Backends For Frontends pattern (#300) Implements the BFF pattern with two client-specific gateways (MobileBff, DesktopBff) aggregating shared downstream services (AuthService, CartService, OrderService, SupplierService) into client-tailored response shapes. Closes #300 * Rename SupplierService lookup key to productName for clarity The service is looked up by product name throughout the codebase, not an actual product ID as the previous naming implied. * Address review feedback: remove unnecessary compact constructors, add InMemory* service tests
This commit is contained in:
1 parent
c298e94d96
commit
1673930bc0
37 files changed
+1930
No files matched your search
@@ -0,0 +1,148 @@
|
||||
---
|
||||
title: "Backends For Frontends Pattern in Java: Tailoring APIs to Client Needs"
|
||||
shortTitle: Backends For Frontends
|
||||
description: "Learn the Backends For Frontends (BFF) design pattern in Java. Understand how to give each client type its own dedicated backend service, with real-world examples, code, and diagrams."
|
||||
category: Architectural
|
||||
language: en
|
||||
tag:
|
||||
- API design
|
||||
- Architecture
|
||||
- Client-server
|
||||
- Decoupling
|
||||
- Microservices
|
||||
---
|
||||
|
||||
## Also known as
|
||||
|
||||
* Backend For Frontend
|
||||
* BFF Pattern
|
||||
|
||||
## Intent of Backends For Frontends Pattern
|
||||
|
||||
Provide each client-side application (mobile, desktop, chatbot, and so on) with its own dedicated
|
||||
backend service, so every client gets an API shaped exactly for its own needs instead of sharing
|
||||
one general-purpose backend with every other client.
|
||||
|
||||
## Detailed Explanation of Backends For Frontends Pattern with Real-World Examples
|
||||
|
||||
Real-world example
|
||||
|
||||
> Imagine a retail company whose mobile app, desktop back-office tool, and support chatbot all
|
||||
> need customer, cart, order and supplier data -- but a phone screen wants a short summary while
|
||||
> the back-office desktop tool wants full order and stock detail. Rather than exposing one shared
|
||||
> API that every client has to filter or over-fetch from, the company stands up a small BFF service
|
||||
> for the mobile clients and a separate BFF service for the intranet clients. Each BFF calls only
|
||||
> the downstream microservices its client needs and returns a payload shaped for that client.
|
||||
|
||||
In plain words
|
||||
|
||||
> Give every kind of client its own tailor-made backend, instead of forcing all clients through one
|
||||
> one-size-fits-all API.
|
||||
|
||||
Sam Newman, who popularized the pattern, says
|
||||
|
||||
> Create separate backend services to be consumed by specific frontend applications or interfaces.
|
||||
|
||||
## Architecture Diagram
|
||||
|
||||
```
|
||||
node mobile{
|
||||
component iosapp as "ios app"
|
||||
component androidapp as "android app"
|
||||
}
|
||||
node intranet{
|
||||
component desktop as "desktop app"
|
||||
component chatbot
|
||||
}
|
||||
component bff as "BFF server"{
|
||||
component iosbff as "ios BFF"
|
||||
component androidbff as "android BFF"
|
||||
component chatbotbff as "chatbot BFF"
|
||||
component desktopbff as "desktop BFF"
|
||||
}
|
||||
node intranetserv as "intranet services server"{
|
||||
component ss as "supplier service API"
|
||||
}
|
||||
cloud onlypublic as "public cloud"{
|
||||
component cas as "customer authentication service API"
|
||||
component cs as "cart service API"
|
||||
}
|
||||
cloud cloudserv as "managed cloud"{
|
||||
component os as "order service API"
|
||||
}
|
||||
iosapp -- iosbff
|
||||
androidapp -- androidbff
|
||||
chatbot -- chatbotbff
|
||||
desktop -- desktopbff
|
||||
iosbff -- cas
|
||||
androidbff -- cas
|
||||
iosbff -- cs
|
||||
androidbff -- cs
|
||||
iosbff -- os
|
||||
androidbff -- os
|
||||
chatbotbff -- os
|
||||
desktopbff -- os
|
||||
chatbotbff -- ss
|
||||
desktopbff -- ss
|
||||
```
|
||||
|
||||
This example implements a simplified version of the diagram above with two client-facing BFFs
|
||||
instead of four, to keep the demo focused: a **Mobile BFF** standing in for the ios/android BFFs,
|
||||
and a **Desktop BFF** standing in for the desktop/chatbot BFFs. Both call into the same shared
|
||||
downstream services (`AuthService`, `OrderService`), while `CartService` is only used by the
|
||||
Mobile BFF and `SupplierService` is only reachable from the Desktop BFF, matching the fan-out
|
||||
shown in the diagram.
|
||||
|
||||
## Class Diagram
|
||||
|
||||

|
||||
|
||||
## When to Use the Backends For Frontends Pattern in Java
|
||||
|
||||
* Different client types (mobile, web, desktop, voice/chat) need meaningfully different shapes,
|
||||
granularity, or aggregation of the same underlying data.
|
||||
* A single shared API has grown a large number of client-specific conditional branches, optional
|
||||
fields, or query parameters to accommodate every consumer.
|
||||
* Different client teams need to iterate on their own API independently without coordinating
|
||||
changes through one shared backend team.
|
||||
* Some clients (e.g. mobile) need aggressively trimmed payloads for bandwidth/latency reasons,
|
||||
while others (e.g. an internal desktop tool) need much richer data.
|
||||
|
||||
## Benefits and Trade-offs of Backends For Frontends Pattern
|
||||
|
||||
Benefits:
|
||||
|
||||
* Each client gets an API optimized for its own needs, improving performance and simplicity on
|
||||
the client side.
|
||||
* Client teams can evolve their BFF independently, reducing cross-team coordination.
|
||||
* Downstream microservices stay generic and reusable; client-specific logic lives in the BFF
|
||||
layer instead of leaking into shared services.
|
||||
|
||||
Trade-offs:
|
||||
|
||||
* Introduces additional services to build, deploy, and operate.
|
||||
* Logic that is genuinely shared across clients can end up duplicated across BFFs if not
|
||||
carefully factored out.
|
||||
* Adds an extra network hop between the client and the downstream services.
|
||||
|
||||
## How to Implement Backends For Frontends Pattern in Java
|
||||
|
||||
1. Identify the distinct client types that need meaningfully different data shapes.
|
||||
2. Define the downstream services each client's data actually depends on (`AuthService`,
|
||||
`CartService`, `OrderService`, `SupplierService` in this example).
|
||||
3. Create one BFF per client type, implementing a shared `ClientBff<T>` contract, where each BFF
|
||||
only depends on the downstream services its client needs.
|
||||
4. Have each BFF aggregate and reshape the downstream data into a response DTO tailored to its
|
||||
client (`MobileDashboardResponse`, `DesktopDashboardResponse`).
|
||||
5. Wire the client applications to call their own BFF rather than the downstream services
|
||||
directly.
|
||||
|
||||
## Source Code
|
||||
|
||||
* [Pattern: Backends For Frontends](https://samnewman.io/patterns/architectural/bff/) by Sam Newman
|
||||
* [Microservices Patterns: With examples in Java](https://www.amazon.com/Microservices-Patterns-examples-Chris-Richardson/dp/1617294543) by Chris Richardson
|
||||
|
||||
## References and Credits
|
||||
|
||||
* [Building Microservices](https://www.oreilly.com/library/view/building-microservices-2nd/9781492034018/) by Sam Newman
|
||||
* [Pattern: Backend for frontend (microservices.io)](https://microservices.io/patterns/apigateway.html)
|
||||
Reference in new issue
Block a user