Prompt
How do I aggregate multiple APIs with GraphQL?
Latest observation
To aggregate multiple APIs with GraphQL, you typically create a GraphQL gateway or server that sits in front of the APIs and exposes a single schema to clients. That server resolves GraphQL fields by calling the underlying REST/GraphQL/SOAP/etc. services and combining the results.
Common approaches
1) Build a GraphQL layer over existing APIs
You define GraphQL types and resolvers that fetch data from multiple sources.
Example:
Usercomes from a user serviceOrderscomes from an order serviceProfilecomes from a profile service
A query like:
query {
user(id: "1") {
id
name
orders {
id
total
}
}
}
might trigger:
- one request to the user API
- one request to the orders API
- then merge the results in the resolver
2) Use GraphQL Federation
If you have multiple teams/services, each service can own part of the schema, and a gateway composes them into one graph.
Best when:
- services are independently deployed
- each service owns its domain
- you want a scalable microservices architecture
Popular tooling:
- Apollo Federation
- GraphQL Mesh (can also wrap existing APIs)
- Hasura for some data sources
3) Use schema stitching or API composition
A gateway combines multiple GraphQL schemas into one unified schema. This is more common when your sources are already GraphQL APIs.
Typical architecture
Client -> GraphQL Gateway -> Service A / Service B / Service C
The gateway:
- authenticates requests
- validates queries
- fetches data from APIs
- maps/normalizes responses
- batches requests to avoid overfetching
- handles caching, retries, and errors
Basic implementation idea
Schema
type User {
id: ID!
name: String!
orders: [Order!]!
}
type Order {
id: ID!
total: Float!
}
type Query {
user(id: ID!): User
}
Resolver example
const resolvers = {
Query: {
user: async (_, { id }) => {
const res = await fetch(`https://user-api.example.com/users/${id}`);
return res.json();
},
},
User: {
orders: async (user) => {
const res = await fetch(`https://order-api.example.com/users/${user.id}/orders`);
return res.json();
},
},
};
Important best practices
Avoid N+1 requests
If you query many users and each user fetches orders separately, you can end up with many API calls. Use:
DataLoader- batching
- caching
Normalize data
Different APIs may use different field names or formats. Your GraphQL layer should map them into a consistent schema.
Handle errors gracefully
One API failure shouldn’t necessarily break the whole query. Return partial data when appropriate.
Secure the gateway
- enforce auth at the gateway
- propagate identity/roles to downstream services
- limit query depth/complexity to prevent abuse
Cache smartly
Caching can help a lot when aggregating multiple APIs, especially for repeated nested fields.
When to use GraphQL for aggregation
Use it if:
- clients need data from multiple APIs in one request
- different clients need different shapes of the same data
- you want to reduce round trips and client-side orchestration
Avoid it if:
- your system is small and simple
- the overhead of maintaining the graph is not worth it
- the backend services are already well-optimized and simple enough
Tools to consider
- Apollo Server + Federation
- GraphQL Mesh
- Hasura
- Hot Chocolate (.NET)
- graphql-tools / schema stitching
- Nexus or Pothos for schema building in Node.js
If you want, I can show you:
- a simple Node.js example that aggregates two REST APIs with GraphQL, or
- an Apollo Federation setup for multiple services.