API Composition
API Composition implements cross-service queries by calling each owning service and joining the results in memory. It is the simplest read strategy for a database-per-service architecture.
API Composition answers a question that requires data from several services. Because each service owns its own database, you cannot run a single SQL join across them. Instead, a composer calls each service that owns part of the answer and combines the results in application memory. It is the simplest way to implement cross-service queries in a database-per-service architecture.
How It Works
A component called the API composer receives the query, identifies which services hold the needed data, and invokes them, often in parallel. It then performs an in-memory join, filter, or aggregation on the collected responses and returns a unified result. The composer can be a dedicated service, a gateway, or a backend-for-frontend.
For example, to display an order with its customer and shipping details, the composer calls the order, customer, and shipping services and merges their responses.
The composer should call independent services concurrently and only sequence calls when one result feeds the next. Caching frequently requested compositions and applying per-call timeouts keep latency predictable. Because the composer holds no canonical data of its own, it must treat every downstream as a potentially slow or failing dependency and shape its contract around partial availability.
When to Use It
Use API Composition when a query needs data from a small number of services, the join is simple, and the data volumes are modest. It keeps each service's data private and avoids a shared database. It is the natural read-side companion to a database-per-service design when CQRS would be overkill.
Avoid it when the join is large, requires sorting or pagination across services, or fans out to many services, because in-memory joins become slow and expensive.
It is a good first choice precisely because it requires no new infrastructure; you can start with composition and introduce a CQRS read model later only for the specific queries that outgrow it.
Trade-offs
The pattern is simple and requires no extra data store, but it pushes join work into the application, which can be inefficient for large datasets. Calling several services raises the chance that one is slow or down, so the composer needs timeouts, partial-result handling, and retries. Consistency is eventual: the services may return data from slightly different points in time. When these limits bite, a CQRS read model is the alternative. As a rule of thumb, if a composition repeatedly fans out to many services or needs cross-service sorting and pagination, that is the signal to graduate the query to a precomputed read model.
Related Patterns
API Composition and CQRS are the two ways to implement queries across a Database per Service. Gateway Aggregation is API Composition performed at the gateway. The Aggregator pattern is the general structural form.
Example
A customer dashboard shows recent orders, loyalty points, and open support tickets. These live in three services. A composer service fires three parallel requests, waits with a timeout, and assembles a single JSON document. If the support service times out, it returns the orders and points with the tickets section marked unavailable, so the dashboard still renders.