How an API Layer Fixed Our Supply‑Chain Microservice Chaos
The article examines a complex supply‑chain system built on Spring Cloud, identifies issues with interface placement and tangled service dependencies, proposes an intermediate API layer and later a BFF pattern, and evaluates the trade‑offs, implementation details, and remaining challenges of these architectural changes.
We built a supply‑chain platform that includes services for products, sales orders, franchisees, store operations, and work orders, serving multiple user roles (head‑office product management, store management, franchisee staff, store staff) and two client apps – one for customers and one for employees/franchisees.
The initial architecture placed a gateway layer (Spring Cloud Zuul) in front of all services. The gateway handled routing, authentication, monitoring, and rate‑limiting, performing load‑balancing when multiple instances of a service existed.
Routing : All requests pass through the gateway, which forwards them to the appropriate backend based on URI.
Authentication : Centralized credential verification.
Monitoring : API request metrics are recorded for performance analysis.
Rate‑limiting & circuit breaking : Protects downstream services from overload or failures.
Problem 1 – Interface placement : During design we struggled to decide whether an interface used by both client apps should live in the store service or the work‑order service. We eventually placed the first interface in the store service and the second in the work‑order service, resulting in unclear responsibility boundaries and low decision efficiency.
Problem 2 – Service dependency hell : A typical operation, such as submitting a work order, must update inventory, sales‑order status, and the work‑order itself. Because many features require cross‑service updates, the call graph became densely tangled, making iteration painful.
Proposed solution – Introduce an API layer : We added a dedicated API layer between the gateway and backend services. This layer has no database; its sole job is to call other services. It must satisfy three requirements:
Aggregation : Combine data from multiple backends into a single response.
Distributed calls : Sequentially invoke several services to achieve a business transaction.
Decoration : Transform or filter backend data (e.g., drop fields, wrap values) before returning to the client.
After inserting the API layer, all requests flow: Gateway → Shared API layer → Backend services . Because the API layer does not own data, the decision about where to place an interface becomes straightforward: if the logic is aggregation, decoration, or distributed calling, it stays in the API layer; if it involves persisting or querying data, the logic remains in the service that owns the data.
Benefits observed :
Reduced indecision about interface placement.
Service‑to‑service dependencies collapsed to a single direction (API layer → backend), dramatically simplifying the dependency graph.
New issue – Client‑specific adaptation : Different front‑ends (App, H5, PC, mini‑program) have varying UI detail requirements, frequent minor field changes, and conflicting compatibility needs during backend releases. This re‑introduces complexity in the API layer.
To address this, we adopted the BFF (Backend‑for‑Frontend) pattern. Each client gets its own dedicated API service that implements the three API‑layer responsibilities but can tailor responses to its specific UI needs. The architecture becomes: Gateway → Client‑specific BFF → Shared backend services . Because each BFF knows only one client, it can omit generic compatibility logic, resulting in lighter, faster APIs and independent release cycles.
In practice the system grew to nearly 100 services, requiring departmental API services. We therefore deployed multiple API services, each owned by a department, while keeping the same gateway and backend services.
Technical implementation details :
Gateway: Spring Cloud Zuul, registers API services in ZooKeeper, forwards calls via Feign.
API service: Plain Spring Web application without its own database; performs aggregation, distributed calls, and decoration via Feign.
Backend services: Spring Web services with their own databases and caches.
Code duplication among API services emerged because many functions (e.g., user authentication, common data transformations) were repeated across PC API, App API, etc. Three mitigation strategies were evaluated:
Package shared code into a JAR and let each API service depend on it.
Extract shared logic into a separate CommonAPI service that other APIs call.
Leave the duplicate code in place when the maintenance cost is lower than the overhead of a shared library or service.
After weighing the trade‑offs, the team kept the duplicate code because the effort to maintain a shared artifact outweighed the benefits.
We also considered removing pure proxy APIs altogether. Two ideas were explored:
Let the gateway call backend services directly, bypassing the API layer – rejected because it would break the layered architecture.
Introduce an interceptor in the API layer that forwards unmapped URIs to the backend – rejected due to added complexity and limited gain.
Consequently, we retained the simple proxy implementation.
Team organization : A dedicated API team owns all API services, while backend services are split into domain‑focused squads. This separation gives the API team a holistic view of the system, reduces overlapping responsibilities, but also risks the API team handling only simple business logic, making retention harder.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Architect
Professional architect sharing high‑quality architecture insights. Topics include high‑availability, high‑performance, high‑stability architectures, big data, machine learning, Java, system and distributed architecture, AI, and practical large‑scale architecture case studies. Open to ideas‑driven architects who enjoy sharing and learning.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
