Backend Development 11 min read

Designing an API Layer and BFF Architecture for a Large‑Scale Supply Chain System

This article explains how a complex supply‑chain platform with dozens of services and two client apps can be reorganized by introducing a gateway, an API aggregation layer, and a Backend‑for‑Frontend (BFF) pattern to reduce service coupling, simplify interface placement, and improve client‑specific adaptations.

Architect's Guide
Architect's Guide
Architect's Guide
Designing an API Layer and BFF Architecture for a Large‑Scale Supply Chain System

In a previously designed supply‑chain system, there are services for products, sales orders, franchisees, store operations, work orders, etc., involving many user roles such as headquarters product management, store management, franchise employees, and store staff, plus two client apps: one for customers and one for company employees and franchisees.

The overall architecture includes a gateway layer responsible for routing, authentication, monitoring, and rate‑limiting/circuit‑breaking.

Routing: all requests pass through the gateway, which directs them to the appropriate backend service based on URI and performs load balancing when multiple instances exist.

Authentication: centralized authentication and authorization for all requests.

Monitoring: records API request data; an API management system provides monitoring and performance analysis.

Rate limiting & circuit breaking: protects backend services from overload and isolates failing services.

Two problems are identified. Case 1 concerns where to place interfaces used by the two client apps, leading to indecision and inconsistent responsibility division. Interfaces were initially placed in store service and work‑order service, creating tangled call relationships.

Case 2 shows that a single user action (e.g., submitting a work order) often updates multiple services (inventory, sales order status, work order), causing chaotic inter‑service dependencies.

To solve these issues, an API layer is introduced. This layer must satisfy three needs:

Aggregation: combine data from multiple backend services into a single response.

Distributed calls: invoke several backend services sequentially to modify data.

Decoration: reshape or filter backend data (e.g., remove fields, wrap data) before returning to the client.

The new architecture routes all requests through the gateway to a shared API layer, which has no own database but merely calls other services.

While this resolves the first two problems, a new challenge appears: different clients (App, H5, PC, mini‑program) have varying UI requirements, leading to three issues—client‑specific data needs, frequent minor changes, and increased compatibility complexity.

The solution is to adopt the Backend‑for‑Frontend (BFF) pattern, creating a dedicated API service for each client type. Each BFF can be optimized for its client, eliminating cross‑client compatibility logic and allowing independent release cycles.

In practice, the system contains nearly 100 services across domains such as new retail, finance, after‑sales, and customer service, requiring hundreds of developers. To achieve decoupling and independent scheduling, each department maintains its own API services, and front‑end components are modularized per department.

The technical stack remains Spring Cloud‑based, with Zuul as the gateway, Feign for inter‑service calls, and Spring Web for both API and backend services. The gateway registers API services in ZooKeeper.

API services have no database; they perform aggregation, distributed calls, and decoration via Feign.

Backend services are standard Spring Web services with their own databases and caches.

Code duplication among API services is addressed in three ways: sharing common code via a JAR, extracting shared logic into a separate CommonAPI service, or, when duplication is minimal, keeping the code as‑is.

For pure proxy APIs where the request simply forwards to a backend, options such as bypassing the API layer or adding an interceptor were considered but rejected due to added complexity; the team decided to retain the simple proxy code.

Finally, development responsibilities are split: a dedicated API team maintains all API services, while backend services are divided into domain‑specific teams, ensuring overall architectural awareness while acknowledging the trade‑off of simpler business logic for the API team.

backend architectureMicroservicesAPI GatewayBFFSpring Cloudservice decomposition
Architect's Guide
Written by

Architect's Guide

Dedicated to sharing programmer-architect skills—Java backend, system, microservice, and distributed architectures—to help you become a senior architect.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.