What is Federation?
Federation allows you to compose multiple GraphQL services into a single graph.
graphql
# User service
type User @key(fields: "id") {
id: ID!
name: String!
email: String!
}
# Posts service
type Post {
id: ID!
title: String!
content: String!
author: User
}
extend type User @key(fields: "id") {
id: ID! @external
posts: [Post]
}Apollo Federation
Subgraph Setup
javascript
// posts-service/index.js
import { ApolloServer } from '@apollo/server';
import { buildSubgraphSchema } from '@apollo/subgraph');
const typeDefs = gql`
extend type User @key(fields: "id") {
id: ID! @external
posts: [Post]
}
type Post @key(fields: "id") {
id: ID!
title: String!
author: User
}
`;
const resolvers = {
Post: {
author(post) {
return { __typename: 'User', id: post.authorId };
}
},
User: {
posts(user) {
return db.posts.filter({ authorId: user.id });
}
}
};
const server = new ApolloServer({
schema: buildSubgraphSchema([{ typeDefs, resolvers }])
});Gateway Setup
javascript
// gateway/index.js
import { ApolloGateway } from '@apollo/gateway';
import { ApolloServer } from '@apollo/server';
const gateway = new ApolloGateway({
supergraphSdl: new IntrospectAndCompose({
subgraphs: [
{ name: 'users', url: 'http://localhost:4001' },
{ name: 'posts', url: 'http://localhost:4002' }
]
})
});
const server = new ApolloServer({ gateway });Federation Directives
@key
graphql
type Product @key(fields: "id") {
id: ID!
name: String!
price: Float!
}@requires
graphql
type Review @key(fields: "id") {
id: ID!
product: Product
rating: Int
}
extend type Product @key(fields: "id") {
id: ID! @external
reviews: [Review]
avgRating: Int @requires("price")
}@provides
graphql
type User @key(fields: "id") {
id: ID!
name: String! @provides("email")
}@external
graphql
extend type Product @key(fields: "sku") {
sku: ID! @external
price: Int @external
weight: Int @external
}Entity Resolver
javascript
const resolvers = {
Product: {
__resolveReference(reference) {
return db.products.findBySku(reference.sku);
}
}
};Query Planning
javascript
// Gateway automatically plans queries
# Query:
query GetProductWithReviews($id: ID!) {
product(id: $id) {
name
reviews {
rating
author {
name
}
}
}
}
# Execution plan:
1. Products subgraph: product(id, name)
2. Reviews subgraph: reviews(product, rating)
3. Users subgraph: user(id, name)Best Practices
- 1Separation of concerns: Each service owns its types
- 2Minimal coupling: Use @key sparingly
- 3Entity design: Choose primary keys carefully
- 4Performance: Monitor query planning overhead
- 5Testing: Test subgraphs independently
Schema Registry
bash
# Apollo Studio
# Publish subgraph schema
rover subgraph publish my-graph@current \
--name products \
--schema ./products/schema.graphql \
--routing-url http://products-service:4001Monitoring
javascript
// Trace query execution
const gateway = new ApolloGateway({
supergraphSdl,
// Collect tracing data
plugins: [ApolloServerPluginUsageReporting()]
});Build federated graphs at scale!