Skip to main content

Backend Aggregation

Call two upstream services from a single workflow and return a merged response to the client. The client makes one request; the gateway calls both backends, combines the results, and returns a unified JSON object.

Typical scenario: A mobile app needs a "user profile" screen populated with data from two separate services — a user service (name, email, plan) and an activity service (last login, usage stats). Instead of two client-side calls, the gateway aggregates them into one response.


Prerequisites

  • You are signed in to the Management UI as an admin or editor
  • Two upstream HTTP services are accessible from the gateway network:
    • User service: https://user-service.internal/users/{userId}
    • Activity service: https://activity-service.internal/activity/{userId}
  • A collection (e.g. platform-api) and proxy (e.g. GET /profile/{userId}) are already created

Workflow overview

The workflow runs two HTTP calls in parallel, merges their outputs, builds the final JSON, and returns it.


Step 1 — Open the workflow canvas

  1. Open Collections, select platform-api.
  2. Open the GET /profile/{userId} proxy.
  3. Click the Workflow tab to open the canvas.

Step 2 — Add the trigger node

The http_trigger node is automatically present and represents the incoming request. It exposes the request path, headers, and query parameters to downstream nodes.

Confirm the trigger is configured with:

  • Path parameter: userId (matches the proxy path {userId})

Step 3 — Add parallel HTTP request nodes

You will call both services in parallel using a parallel_node feeding into two http_request_node instances.

  1. Drag a Parallel node from the node palette and connect it from http_trigger.
  2. In the parallel node settings, set Branches: 2.

Branch 1 — User service:

  1. Add an http_request_node on the first parallel branch.
  2. Configure:
    • Method: GET
    • URL: https://user-service.internal/users/{{trigger.params.userId}}
    • Headers: Content-Type: application/json
  3. Name this node fetch-user.

Branch 2 — Activity service:

  1. Add an http_request_node on the second parallel branch.
  2. Configure:
    • Method: GET
    • URL: https://activity-service.internal/activity/{{trigger.params.userId}}
    • Headers: Content-Type: application/json
  3. Name this node fetch-activity.
tip

Use {{trigger.params.userId}} to pass the path parameter from the incoming request into each upstream URL.


Step 4 — Merge the responses

  1. Drag a Merge node and connect both fetch-user and fetch-activity as inputs.
  2. The merge node waits for both branches to complete before continuing.
  3. Name this node merge-results.

After the merge node, both upstream responses are available as:

  • {{fetch-user.response.body}}
  • {{fetch-activity.response.body}}

Step 5 — Build the unified response with a Set node

Use a set_node to assemble the merged JSON object you want to return.

  1. Drag a Set node and connect it from merge-results.
  2. Configure the output fields:
{
"userId": "{{trigger.params.userId}}",
"name": "{{fetch-user.response.body.name}}",
"email": "{{fetch-user.response.body.email}}",
"plan": "{{fetch-user.response.body.plan}}",
"lastLogin": "{{fetch-activity.response.body.lastLogin}}",
"apiCallsThisMonth": "{{fetch-activity.response.body.usage.calls}}"
}
  1. Name this node build-profile.

Step 6 — Return the response

  1. Drag a Response node and connect it from build-profile.
  2. Configure:
    • Status: 200
    • Body: {{build-profile.output}}
    • Content-Type: application/json

Step 7 — Save and publish

  1. Click Save on the workflow canvas.
  2. Return to the proxy settings and click Publish to make the endpoint live.

Verify

Test the aggregated endpoint:

curl -i https://gateway.example.com/platform-api/profile/user-42 \
-H "X-Client-ID: <client-id>" \
-H "Authorization: Bearer <token>" \
-H "X-Profile-ID: <profile-id>"

Expected response:

HTTP/1.1 200 OK
Content-Type: application/json

{
"userId": "user-42",
"name": "Alice Nguyen",
"email": "[email protected]",
"plan": "pro",
"lastLogin": "2026-03-09T14:23:00Z",
"apiCallsThisMonth": 1842
}

Edge case — one backend fails:

If either upstream returns a non-2xx status, the workflow raises an error. To handle partial failures gracefully, add a condition_node after each http_request_node that branches on status code, returning a default value when the service is unavailable. See the Retry and Fallback recipe for the full pattern.


Observability

Open Logs → Request Logs and select the request to see:

  • Which workflow steps ran
  • Upstream response times for both services
  • The final response body returned to the client

Next steps