Implementing GraphQL Federation
1. Understanding Federated Architecture
┌──────────────┐
Client─▶│ Gateway │ (composes supergraph)
└──────┬───────┘
┌──────┼───────┐
▼ ▼ ▼
Users Orders Products
subgraph subgraph subgraph
| Component | Role |
|---|---|
| Subgraph | Independent service owning entities |
| Supergraph | Composed schema across all subgraphs |
| Router/Gateway | Plans + executes queries |
| Apollo Federation 2 | Current spec |
2. Defining Entity Types
Example: Entity with @key
# users subgraph
type User @key(fields: "id") {
id: ID!
email: String!
name: String!
}
3. Extending External Types
Example: Extend User in orders subgraph
# orders subgraph
extend type User @key(fields: "id") {
id: ID! @external
orders: [Order!]!
}
type Order @key(fields: "id") {
id: ID!
total: Money!
}
4. Referencing External Fields
| Directive | Use |
|---|---|
| @external | Field defined in another subgraph |
| @requires(fields) | Need fields from owner before resolving |
| @provides(fields) | Can return owner's fields without callback |
5. Requiring External Fields
Example: @requires
extend type Product @key(fields: "id") {
id: ID! @external
weight: Int @external
shippingCost: Money! @requires(fields: "weight")
}
6. Providing External Fields
Example: @provides
type Review @key(fields: "id") {
id: ID!
author: User! @provides(fields: "username")
body: String!
}
7. Resolving Entity References
Example: __resolveReference
const resolvers = {
User: {
__resolveReference: ({ id }, { loaders }) => loaders.userById.load(id)
}
};
8. Understanding Federated Queries
Query: { user(id:1) { name orders { total } } }
Gateway plans:
1) Fetch User(id:1).name from users subgraph
2) Fetch User._entities([{__typename:User, id:1}]).orders.total from orders subgraph
3) Merge results
9. Implementing Federation Directives
| Directive | Purpose |
|---|---|
| @key(fields) | Declare entity primary key |
| @external | Field owned elsewhere |
| @requires(fields) | Need owner data first |
| @provides(fields) | Inline owner data when fetched here |
| @shareable | Field can be defined in multiple subgraphs |
| @override(from) | Take ownership from another subgraph |
| @inaccessible | Hide from supergraph |
| @tag(name) | Mark for governance/policies |
10. Handling Cross-service Joins
| Concern | Mitigation |
|---|---|
| Latency stack-up | Use @provides to avoid extra hops |
| N+1 across subgraphs | Batch via _entities query |
| Failure isolation | Subgraph down → null + error, not full failure |