API Composition
API Composition combines data or operations from multiple backend services behind a single client-facing API boundary. It simplifies clients by moving cross-service coordination into an aggregation layer, while introducing trade-offs around latency, failure handling, and coupling.
An API Composition layer receives a client request, calls two or more backend services, and combines their responses into one result. For example, an order endpoint might retrieve order details from an Order Service and customer information from a Customer Service before returning a single response.
The composition layer can be implemented as a dedicated service, an API gateway capability, or another backend boundary. Its main purpose is to keep clients from needing knowledge of multiple service endpoints, response formats, and coordination rules.
A synchronous composition commonly makes several network calls during one request. Independent calls can sometimes execute concurrently to reduce total latency, but the composer must still define behavior when one dependency times out, returns an error, or provides incomplete data.
Composition also affects ownership and coupling. The composing layer should generally coordinate services without taking over their domain responsibilities. Careful response contracts, timeouts, retries, observability, and fallback policies are important when the composed operation crosses service boundaries.
Key points
- One client-facing operation can aggregate results from multiple backend services.
- The composition layer hides service topology and coordination from clients.
- Independent downstream calls may be executed concurrently to reduce latency.
- Partial failures, timeouts, retries, and fallback behavior must be designed explicitly.
- Composition should coordinate domain services rather than duplicate their business ownership.
Interview questions
What is API Composition, and why would you use it in a microservices system?
API Composition exposes a single client-facing operation that obtains information from multiple backend services and combines the results. It reduces the amount of service-to-service knowledge required by clients. This can make a client simpler when a screen or workflow needs data owned by several services. The trade-off is that the composition layer becomes responsible for coordination and downstream failure handling.
How would you reduce latency in an API Composition endpoint?
I would first identify which downstream calls are independent and execute them concurrently rather than waiting for each one sequentially. In Java, asynchronous HTTP clients or `CompletableFuture` can represent concurrent work. I would also set explicit timeouts and measure downstream latency with distributed tracing. Caching may help for suitable read-heavy data, but it should be applied according to freshness requirements.
How should an API Composer handle a downstream service failure?
The correct behavior depends on whether the failed dependency is required for a valid response. For a mandatory dependency, the composer may return an appropriate error after applying bounded timeout and retry policies. For optional information, it may return a partial response with an explicit indication that the optional data is unavailable. The policy should be documented rather than allowing accidental behavior to emerge from exception handling.
What are the main architectural trade-offs of API Composition?
Composition simplifies clients and can provide a view tailored to a particular use case, but it introduces another coordination point and adds network dependencies to the request path. The composer can become coupled to several service contracts and may accumulate domain logic if its responsibilities are not controlled. It also has to manage latency, partial failures, timeouts, retries, and observability across distributed calls. I would keep domain ownership in the underlying services while keeping the composer focused on orchestration and response shaping.