Add Backends For Frontends (BFF) pattern (#300)#3543
Conversation
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 iluwatar#300
PR SummaryImplements the Backends For Frontends (BFF) pattern via a new module Changes
autogenerated by presubmit.ai |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #3543 +/- ##
============================================
+ Coverage 83.24% 83.32% +0.08%
- Complexity 4025 4056 +31
============================================
Files 1060 1074 +14
Lines 14246 14333 +87
Branches 686 689 +3
============================================
+ Hits 11859 11943 +84
- Misses 2100 2106 +6
+ Partials 287 284 -3 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
The service is looked up by product name throughout the codebase, not an actual product ID as the previous naming implied.
HattoriHenzo
left a comment
There was a problem hiding this comment.
My global review or this PR:
- Add a Web Front End BFF
- In the unit tests add InMemory*.java unit tests
| */ | ||
| public record Order(String id, String productName, String status) { | ||
| /** No additional validation required. */ | ||
| public Order { |
There was a problem hiding this comment.
You don't need a default constructor here. The JVM will define a default canonical constructor. The same rule applies to all the models.
| </dependency> | ||
| <dependency> | ||
| <groupId>org.slf4j</groupId> | ||
| <artifactId>slf4j-api</artifactId> |
There was a problem hiding this comment.
No logging instruction in called in the code. You can remove this dependency if not using it.
There was a problem hiding this comment.
Removed the compact constructors from all 6 records, good catch. They originally existed to satisfy checkstyle:check@validate (which flags empty {} bodies under WhitespaceAround), but I confirmed CI (mvnw clean verify) doesn't actually run Checkstyle, and the same pattern already exists unaddressed in converter/data-transfer-object, so I dropped the workaround to match the rest of the repo.
Also added InMemory* unit tests for all four service implementations (100% coverage on those classes now, closing the gap Codecov flagged), and confirmed slf4j-api is a genuinely required direct dependency — App.java uses it and it's not provided transitively.
On the Web BFF suggestion — issue #300's acceptance criteria only called for two client-specific backends, which Mobile/Desktop satisfy. Happy to add a Web BFF as a follow-up PR, or in this one if you'd prefer.
There was a problem hiding this comment.
Thanks for the feedback.
… InMemory* service tests
There was a problem hiding this comment.
✅ LGTM!
Review Summary
Commits Considered (3)
- 2a97a22: Address review feedback: remove unnecessary compact constructors, add InMemory* service tests
- 3b1d5ca: 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.
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
Files Processed (30)
- backends-for-frontends/README.md (1 hunk)
- backends-for-frontends/etc/backends-for-frontends.png (0 hunks)
- backends-for-frontends/etc/backends-for-frontends.urm.puml (1 hunk)
- backends-for-frontends/pom.xml (1 hunk)
- backends-for-frontends/src/main/java/com/iluwatar/bff/App.java (1 hunk)
- backends-for-frontends/src/main/java/com/iluwatar/bff/bff/ClientBff.java (1 hunk)
- backends-for-frontends/src/main/java/com/iluwatar/bff/bff/DesktopBff.java (1 hunk)
- backends-for-frontends/src/main/java/com/iluwatar/bff/bff/MobileBff.java (1 hunk)
- backends-for-frontends/src/main/java/com/iluwatar/bff/bff/package-info.java (1 hunk)
- backends-for-frontends/src/main/java/com/iluwatar/bff/dto/DesktopDashboardResponse.java (1 hunk)
- backends-for-frontends/src/main/java/com/iluwatar/bff/dto/MobileDashboardResponse.java (1 hunk)
- backends-for-frontends/src/main/java/com/iluwatar/bff/dto/package-info.java (1 hunk)
- backends-for-frontends/src/main/java/com/iluwatar/bff/model/CartItem.java (1 hunk)
- backends-for-frontends/src/main/java/com/iluwatar/bff/model/Order.java (1 hunk)
- backends-for-frontends/src/main/java/com/iluwatar/bff/model/Product.java (1 hunk)
- backends-for-frontends/src/main/java/com/iluwatar/bff/model/SupplierRecord.java (1 hunk)
- backends-for-frontends/src/main/java/com/iluwatar/bff/model/User.java (1 hunk)
- backends-for-frontends/src/main/java/com/iluwatar/bff/model/package-info.java (1 hunk)
- backends-for-frontends/src/main/java/com/iluwatar/bff/package-info.java (1 hunk)
- backends-for-frontends/src/main/java/com/iluwatar/bff/service/AuthService.java (1 hunk)
- backends-for-frontends/src/main/java/com/iluwatar/bff/service/CartService.java (1 hunk)
- backends-for-frontends/src/main/java/com/iluwatar/bff/service/OrderService.java (1 hunk)
- backends-for-frontends/src/main/java/com/iluwatar/bff/service/SupplierService.java (1 hunk)
- backends-for-frontends/src/main/java/com/iluwatar/bff/service/impl/InMemoryAuthService.java (1 hunk)
- backends-for-frontends/src/main/java/com/iluwatar/bff/service/impl/InMemoryCartService.java (1 hunk)
- backends-for-frontends/src/main/java/com/iluwatar/bff/service/impl/InMemoryOrderService.java (1 hunk)
- backends-for-frontends/src/main/java/com/iluwatar/bff/service/impl/InMemorySupplierService.java (1 hunk)
- backends-for-frontends/src/main/java/com/iluwatar/bff/service/impl/package-info.java (1 hunk)
- backends-for-frontends/src/main/java/com/iluwatar/bff/service/package-info.java (1 hunk)
- backends-for-frontends/src/test/java/com/iluwatar/bff/AppTest.java (1 hunk)
Actionable Comments (0)
Skipped Comments (4)
-
backends-for-frontends/src/main/java/com/iluwatar/bff/bff/MobileBff.java [68-68]
enhancement: "Resilience: error handling in BFF"
-
backends-for-frontends/src/main/java/com/iluwatar/bff/bff/DesktopBff.java [66-67]
maintainability: "Maintainability: extract aggregation logic"
-
backends-for-frontends/src/main/java/com/iluwatar/bff/App.java [78-78]
enhancement: "Resilience: demo main"
-
backends-for-frontends/src/test/java/com/iluwatar/bff/AppTest.java [37-40]
test: "Tests: verify end-to-end outputs"
HattoriHenzo
left a comment
There was a problem hiding this comment.
A part from the build that fails, it LGTM.
Summary
Closes #300
Implements the Backends For Frontends (BFF) pattern as a new module,
backends-for-frontends. Two client-specific gateways —MobileBffandDesktopBff— sit in front of a shared set of downstream microservices(
AuthService,CartService,OrderService,SupplierService) and eachaggregates only the services its own client needs, reshaping the result into
a response tailored to that client:
MobileBffcalls Auth + Cart + Order → returns a leanMobileDashboardResponsesuited to a phone screen.
DesktopBffcalls Auth + Order + Supplier → returns a richerDesktopDashboardResponsewith back-office detail a mobile client never needs.This satisfies the issue's acceptance criteria: distinct client-specific backends,
data aggregation from multiple downstream services per BFF, and an optimized,
purpose-built API for each client.
What's included
Product,CartItem,User,Order,SupplierRecord)real microservices
ClientBff<T>contract +MobileBff/DesktopBffimplementationsApp.javademonstrating both BFFs against the same useretc/backends-for-frontends.png+.urm.puml), referencedfrom the README
Verification
mvn -pl backends-for-frontends -am clean test— all tests passingmvn checkstyle:check@validate -pl backends-for-frontends -am— 0 violationsmvn spotless:check -pl backends-for-frontends -B— cleanmvn clean install, module excluded from unrelated flakesbelow) — green
Notes for reviewers
full reactor build and confirmed not caused by this change by reproducing
them in isolation on a clean checkout:
rate-limiting-pattern'sTokenBucketRateLimiterTest.shouldRefillTokensAfterTimeis timing-flaky.
commander's test suite can hitOutOfMemoryError: unable to create native threadlocally depending on OS thread limits, unrelated to this module.WhitespaceAround'sallowEmptyConstructors/allowEmptyTypesproperties are unset (defaultfalse) in the current Checkstyle config, which conflicts with Spotless/Google Java Format's formatting of empty
{}bodies. This affects any recordwith a fully empty body — I counted at least 16 other existing modules with
the same latent construct, which only avoid failing because Checkstyle isn't
bound to the
installlifecycle. I worked around it locally in this module's6 records by giving each a minimal documented compact constructor rather than
a bare empty body, but didn't touch the shared Checkstyle config or any other
module — happy to open a separate follow-up issue for that if it's useful.