GraphQL Federation is a powerful concept that allows you to build a unified GraphQL API across multiple microservices. In a microservices architecture, each service can manage its own schema and data, but with GraphQL Federation, you can combine them into a single cohesive API. This approach improves flexibility, scalability, and makes it easier to evolve individual services without impacting the overall system.In this chapter, we will explore GraphQL Federation in detail, starting with the basics and progressing to advanced concepts, followed by practical examples.
A federated schema consists of multiple individual schemas that work together. The central piece of this is the Apollo Gateway, which serves as the entry point to the unified schema.
Each service can extend another service’s schema, adding types and fields. These extensions allow one service to “join” its schema with another service’s schema.
Resolvers define how to fetch the data for a field in the schema. In federation, resolvers can span across multiple services, ensuring that data from each service is seamlessly combined.
To implement GraphQL Federation, we need to set up the following components:
Install Apollo Server and Federation:
npm install @apollo/server graphql @apollo/gateway
Each service needs to expose its schema with specific directives that allow Federation to combine it with other services.
const { ApolloServer, gql } = require('apollo-server');
const { buildFederatedSchema } = require('@apollo/federation');
const typeDefs = gql`
type User @key(fields: "id") {
id: ID!
username: String!
email: String
}
extend type Query {
user(id: ID!): User
}
`;
const resolvers = {
Query: {
user: (_, { id }) => {
// Fetch user by ID
return { id, username: 'john_doe', email: 'john@example.com' };
},
},
};
const server = new ApolloServer({
schema: buildFederatedSchema([{ typeDefs, resolvers }]),
});
server.listen(4001).then(({ url }) => {
console.log(`Users service running at ${url}`);
});
id
field is used to uniquely identify a User
object.user
query to fetch a user by ID.The Apollo Gateway serves as the entry point for querying federated data. It combines the individual services’ schemas and exposes a unified GraphQL endpoint.
const { ApolloGateway } = require('@apollo/gateway');
const { ApolloServer } = require('@apollo/server');
const gateway = new ApolloGateway({
serviceList: [
{ name: 'users', url: 'http://localhost:4001' },
{ name: 'posts', url: 'http://localhost:4002' },
],
});
const server = new ApolloServer({
gateway,
subscriptions: false, // Disable subscriptions for simplicity
});
server.listen(4000).then(({ url }) => {
console.log(`Gateway running at ${url}`);
});
users
, posts
).When querying federated data, the Apollo Gateway will resolve the fields across the different services based on the schema.
const { ApolloServer, gql } = require('apollo-server');
const { buildFederatedSchema } = require('@apollo/federation');
const typeDefs = gql`
type Post @key(fields: "id") {
id: ID!
title: String!
authorId: ID!
}
extend type Query {
posts: [Post]
}
`;
const resolvers = {
Query: {
posts: () => [
{ id: '1', title: 'GraphQL Federation', authorId: '1' },
],
},
};
const server = new ApolloServer({
schema: buildFederatedSchema([{ typeDefs, resolvers }]),
});
server.listen(4002).then(({ url }) => {
console.log(`Posts service running at ${url}`);
});
Now, you can query data from both the Users
and Posts
services using a unified query.
query {
user(id: "1") {
id
username
}
posts {
id
title
}
}
Testing federated GraphQL APIs involves validating that each service is correctly integrated, data is resolvable, and the schema is properly extended.
const { createTestClient } = require('apollo-server-testing');
const { ApolloServer } = require('@apollo/server');
const server = new ApolloServer({
gateway,
subscriptions: false,
});
const { query } = createTestClient(server);
test('queries data from multiple services', async () => {
const res = await query({ query: GET_USER_AND_POSTS });
expect(res.data.user.username).toBe('john_doe');
expect(res.data.posts[0].title).toBe('GraphQL Federation');
});
GraphQL Federation provides an elegant solution for combining multiple microservices into a unified API while preserving their autonomy. By using the Apollo Gateway and federation principles, developers can build scalable, maintainable, and flexible architectures that simplify data querying across microservices. With proper security, error handling, and performance optimizations, federated GraphQL can be a powerful tool for modern microservices-based applications. Happy coding !❤️