0
0
GraphqlHow-ToBeginner · 4 min read

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 @external on fields extended from other services.
  • Not implementing __resolveReference resolver to fetch entities by key.
  • Running services on wrong ports or not updating the gateway serviceList URLs.

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

ConceptDescription
@keyMarks the unique identifier fields of an entity.
@externalMarks fields that are owned by another service.
extend typeAdds fields to an entity defined in another service.
__resolveReferenceResolver to fetch an entity by its key.
ApolloGatewayCombines 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.