Skip to content

Response Aggregation in API Gateway — Combine Multiple Backend Responses

DodaTech Updated 2026-06-28 4 min read

In this tutorial, you will learn about Response Aggregation in API Gateway. We cover key concepts, practical examples, and best practices to help you master this topic.

Response aggregation is the process of combining data from multiple backend services into a single response at the gateway level, so clients make one request instead of many.

What You'll Learn

  • How aggregation reduces client complexity and network round trips
  • Fan-out requests to multiple backends concurrently
  • Handling partial failures during aggregation

Why It Matters

A dashboard page may need user profile, recent orders, notifications, and product recommendations. Without aggregation, the client makes four sequential requests. With gateway aggregation, the client makes one request, and the gateway fans out to all four services concurrently, returning a single response.

Real-World Use

The Durga Antivirus dashboard shows user info, active subscriptions, recent scan history, and threat alerts. The gateway endpoint /dashboard fans out to four internal services concurrently and combines their responses into one JSON payload for the frontend.

flowchart LR
    Client["Client"] --> GW["Gateway\n/aggregated-endpoint"]
    GW --> S1["Service A"]
    GW --> S2["Service B"]
    GW --> S3["Service C"]
    S1 --> GW
    S2 --> GW
    S3 --> GW
    GW --> Client
    style GW fill:#dbeafe,stroke:#2563eb

Concurrent Fan-Out with asyncio

import asyncio
import aiohttp
from flask import Flask, jsonify

app = Flask(__name__)

SERVICES = {
    "user": "http://user-service:8080/profile",
    "orders": "http://order-service:8080/recent",
    "alerts": "http://alert-service:8080/unread",
}

async def fetch(session, name, url):
    try:
        async with session.get(url, timeout=5) as resp:
            data = await resp.json()
            return name, data, None
    except Exception as e:
        return name, None, str(e)

@app.route("/dashboard")
def dashboard():
    async def aggregate():
        async with aiohttp.ClientSession() as session:
            tasks = [fetch(session, name, url) for name, url in SERVICES.items()]
            results = await asyncio.gather(*tasks)
            payload = {}
            errors = {}
            for name, data, error in results:
                if data:
                    payload[name] = data
                if error:
                    errors[name] = error
            payload["_errors"] = errors
            return payload

    return jsonify(asyncio.run(aggregate()))

Expected response:

{
  "user": {"id": 42, "name": "Alice"},
  "orders": [{"id": 1, "item": "Laptop"}],
  "alerts": [{"type": "threat", "count": 3}],
  "_errors": {}
}

Sequential Fallback Aggregation

Some aggregations require ordered steps. For example, get the user ID first, then fetch that user's orders:

@app.route("/user-orders")
def user_orders():
    user_resp = requests.get("http://user-service:8080/me")
    user = user_resp.json()
    orders_resp = requests.get(f"http://order-service:8080/users/{user['id']}/orders")
    orders = orders_resp.json()
    return jsonify({"user": user, "orders": orders})

Aggregation with Graphql

Some gateways support GraphQL aggregation where the client specifies exactly which data it needs:

@app.route("/graphql", methods=["POST"])
def graphql_aggregation():
    query = request.json.get("query")
    if "user" in query:
        user = requests.get("http://user-service:8080/profile").json()
    if "orders" in query:
        orders = requests.get("http://order-service:8080/recent").json()
    return jsonify({"data": {"user": user, "orders": orders}})

Common Mistakes

1. Sequential Requests When Concurrent Works

Fetching unrelated data sequentially doubles response time. Use asyncio or threading for parallel fan-out.

2. Not Setting Per-Service Timeouts

One slow service blocks the entire aggregation. Set individual timeouts for each backend call.

3. Returning Everything or Nothing

If one service fails, should the whole request fail? Design partial responses with error indicators so clients can display partial data.

4. Ignoring Response Size

Aggregating large datasets creates huge payloads. Allow clients to select which fields they need with query parameters.

5. Tight Coupling to Backend Response Shapes

If a backend changes its response format, aggregation breaks. Use transformation layers to convert backend responses to consistent shapes.

Practice Questions

  1. What problem does response aggregation solve for mobile clients?
  2. When should you use concurrent vs. sequential aggregation?
  3. How should the gateway handle a backend service that times out during aggregation?
  4. Why might aggregation produce very large responses?
  5. How can you decouple aggregation logic from backend response formats?

Answers:

  1. Mobile networks have high latency. One aggregated call replaces multiple sequential calls, reducing total latency from N round trips to 1.
  2. Use concurrent for independent data (profile, orders, alerts). Use sequential when one response depends on another (get user ID first, then orders).
  3. Return partial data with an error field for the failed service. Set per-service timeouts to avoid blocking the entire aggregation.
  4. If backends return large collections, the combined response grows quickly. Implement pagination or field selection to limit size.
  5. Add a transformation layer between backends and the client that normalizes backend responses into consistent client-facing shapes.

Challenge: Design a gateway aggregation endpoint for an e-commerce product page that needs product details, reviews, inventory status, and shipping estimate. Determine which calls run concurrently and which run sequentially.

FAQ

Does aggregation violate Microservices independence?

: No. The gateway aggregates for client convenience. Backend services remain independent and unaware of each other.

How do you cache aggregated responses?

: Cache the aggregated response at the gateway level. Invalidate the cache when any contributing backend's data changes.

Can aggregation work with streaming responses?

: Streaming aggregation is complex. Alternatives include Server-Sent Events or Websocket for real-time aggregated data.

What is the recommended timeout for aggregated backend calls?

: Start with 3-5 seconds per call. The total aggregation timeout should be slightly less than the client timeout.

Does aggregation increase gateway complexity?

: Yes. Each aggregation endpoint needs configuration. Use a declarative aggregation DSL or GraphQL to manage complexity.

Mini Project

Build a gateway aggregation endpoint /profile that fetches user data, recent activity, notification count, and subscription status from four separate mock services. Use concurrent requests, individual 3-second timeouts, and return partial data if any service fails.

What's Next

Continue with Circuit Breaker Pattern in Gateway to prevent cascading failures, or explore Caching in API Gateway for performance optimization.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro