How to Use Apollo Federation for GraphQL Microservices
Use
Apollo Federation by defining multiple GraphQL services with @key directives and then combining them in a ApolloGateway. Each service defines its part of the schema, and the gateway composes them into one unified API.Syntax
Apollo Federation uses special directives like @key to mark entities that can be shared across services. Each service defines a type with @key to identify unique fields. The ApolloGateway composes these services into one schema.
Key parts:
@key(fields: "id"): Marks the primary key for an entity.extend type: Used to add fields to an entity defined in another service.ApolloGateway: Combines all services into one GraphQL endpoint.
graphql
type Product @key(fields: "id") { id: ID! name: String } extend type Product @key(fields: "id") { id: ID! @external price: Float }
Example
This example shows two services: products and reviews. The products service defines a Product type with @key. The reviews service extends Product to add reviews. The ApolloGateway combines them.
javascript
// products.js const { ApolloServer } = require('apollo-server'); const { buildFederatedSchema } = require('@apollo/federation'); const typeDefs = ` type Product @key(fields: "id") { id: ID! name: String } type Query { product(id: ID!): Product } `; const products = [ { id: '1', name: 'Table' }, { id: '2', name: 'Chair' } ]; const resolvers = { Query: { product(_, { id }) { return products.find(p => p.id === id); } }, Product: { __resolveReference(product) { return products.find(p => p.id === product.id); } } }; const server = new ApolloServer({ schema: buildFederatedSchema([{ typeDefs, resolvers }]) }); server.listen({ port: 4001 }); // reviews.js const { ApolloServer } = require('apollo-server'); const { buildFederatedSchema } = require('@apollo/federation'); const typeDefs = ` extend type Product @key(fields: "id") { id: ID! @external reviews: [Review] } type Review { body: String } type Query { _empty: String } `; const reviews = { '1': [{ body: 'Great table!' }], '2': [{ body: 'Comfortable chair.' }] }; const resolvers = { Product: { reviews(product) { return reviews[product.id] || []; } } }; const server = new ApolloServer({ schema: buildFederatedSchema([{ typeDefs, resolvers }]) }); server.listen({ port: 4002 }); // gateway.js const { ApolloServer } = require('apollo-server'); const { ApolloGateway } = require('@apollo/gateway'); const gateway = new ApolloGateway({ serviceList: [ { name: 'products', url: 'http://localhost:4001' }, { name: 'reviews', url: 'http://localhost:4002' } ] }); const server = new ApolloServer({ gateway, subscriptions: false }); server.listen({ port: 4000 }).then(({ url }) => { console.log(`Gateway ready at ${url}`); });
Output
Gateway ready at http://localhost:4000/
Common Pitfalls
Common mistakes when using Apollo Federation include:
- Not marking entities with
@key, so the gateway cannot identify them. - Forgetting to use
@externalon fields extended from other services. - Not implementing
__resolveReferenceresolver to fetch entities by key. - Running services on wrong ports or not updating the gateway
serviceListURLs.
These cause errors like Cannot find entity or incomplete data.
graphql
/* Wrong: Missing @key directive */ type Product { id: ID! name: String } /* Right: Add @key to identify entity */ type Product @key(fields: "id") { id: ID! name: String }
Quick Reference
| Concept | Description |
|---|---|
| @key | Marks the unique identifier fields of an entity. |
| @external | Marks fields that are owned by another service. |
| extend type | Adds fields to an entity defined in another service. |
| __resolveReference | Resolver to fetch an entity by its key. |
| ApolloGateway | Combines multiple services into one GraphQL API. |
Key Takeaways
Use @key directive to mark entities uniquely across services.
Extend types with @external fields to share data between services.
Implement __resolveReference to fetch entities by their keys.
Configure ApolloGateway with all service URLs to compose the schema.
Test each service independently before combining with the gateway.