An aggregate API should not have one universal partial-failure rule. Classify each field or section by whether it is required for a safe user decision, then choose whole-response failure, explicit partial data, bounded stale data, or feature removal. Propagate one deadline and make incompleteness visible in the response contract.
Start with the user’s decision
Consider a checkout summary composed from cart, price, inventory, recommendations, and loyalty services. Current price and purchasable inventory are critical to placing the order. Recommendations are optional. Loyalty points may be useful but can be shown as temporarily unavailable. Returning an apparently complete response with stale price is worse than failing the purchase; failing the whole page because recommendations timed out is unnecessary.
The Gateway Aggregation pattern describes a gateway that fans out to multiple backend services and aggregates results, reducing client chattiness while introducing coupling and a potential bottleneck. The gateway therefore owns a product-level composition contract, not merely parallel HTTP calls.
For every field group, record criticality, freshness limit, dependency deadline, fallback source, and client behavior. This decision matrix should be reviewed by product and domain owners because technical availability choices change what a user may conclude.
Choose an honest response shape
Whole-response failure fits cases where missing data makes the result unsafe or meaningless. Return a stable error, correlation ID, and retry guidance; do not disguise missing authorization or price as an empty value.
Explicit partial data fits independently useful sections. Return the available data plus structured errors keyed to sections, with codes and retryability. Avoid using null for unavailable, absent, not applicable, and unauthorized simultaneously. A typed envelope can distinguish available, stale, unavailable, and redacted.
GraphQL already separates a data member from an errors list in many execution outcomes. The GraphQL over HTTP draft explains how transport status and GraphQL response structure interact. Even outside GraphQL, the useful lesson is to distinguish successful transport from field-level execution outcomes without pretending every partial response is success.
Bounded stale data fits information whose age can be evaluated. Include an asOf time or version and a maximum acceptable age. Never silently fall back to a cache whose age the gateway cannot prove. Feature degradation fits optional elements: omit recommendations and return a capability/status marker so the client can remove the panel rather than render an endless spinner.
Use one deadline and cancel leftovers
Set an end-to-end response deadline, reserve time for aggregation and serialization, and allocate shorter dependency deadlines by criticality and latency history. Start independent calls concurrently. When the response decision is made, cancel work whose result will no longer be used. Do not let every client and dependency apply independent retries; a fan-out gateway can amplify load quickly.
A required dependency may deserve a small retry within the budget if the operation is safe. Optional dependencies usually should not delay the critical path beyond their allocation. Circuit breakers, cached fallbacks, and bulkheads can prevent one degraded dependency from consuming every aggregation worker.
Make partial failure observable
Measure complete, partial, stale, degraded, and failed responses separately. Record dependency outcome, allocated deadline, cache age, and response mode using bounded labels. The top-level success rate alone hides a page that has lost its loyalty section for a week. Include a correlation ID the client can report, while keeping internal topology out of user messages.
Test all combinations for one aggregate: each dependency times out, returns malformed data, returns authorization failure, or responds after the gateway deadline. Verify both response shape and which actions the UI enables.
Take your busiest aggregate endpoint and classify every field as critical, optional, or stale-eligible. Add explicit status and asOf metadata for one optional section, then inject a timeout. The user should still understand exactly what is safe to do.
Sources are linked throughout this guide. Product capabilities can change; consult the linked documentation for your deployment.
Read our editorial approach ↗