Apollo Federation Microservices with Unified GraphQL

Zaheer Ahmad 5 min read min read
Python
Apollo Federation Microservices with Unified GraphQL

Introduction

Apollo Federation is a modern approach to building scalable GraphQL architectures by combining multiple microservices into a single unified GraphQL API—often called a supergraph. Instead of maintaining one large monolithic schema, you split your backend into smaller services (subgraphs), each responsible for a specific domain like users, products, or orders.

In this apollo federation tutorial, you’ll learn how to design and implement GraphQL microservices using federation, and how to stitch them together seamlessly using an Apollo Router or Gateway.

For Pakistani students and developers, this approach is highly relevant. Many startups in cities like Lahore, Karachi, and Islamabad are moving toward microservices to scale their systems. Whether you're building an e-commerce platform where Ahmad manages products and Fatima handles users, or a fintech system dealing with PKR transactions, graphql federation helps you organize your backend efficiently.

Prerequisites

Before diving into this advanced tutorial, you should be comfortable with:

  • Basic GraphQL concepts (queries, mutations, resolvers)
  • Node.js and JavaScript (or TypeScript)
  • REST vs GraphQL differences
  • Express.js or similar backend frameworks
  • Understanding of microservices architecture
  • Familiarity with npm/yarn and CLI tools

If you’re new, consider first studying a GraphQL tutorial and microservices basics.


Core Concepts & Explanation

Subgraphs and the Supergraph

In Apollo Federation, each microservice exposes a subgraph schema. These subgraphs are combined into a supergraph schema that clients interact with.

Example:

  • Users Service → handles user data
  • Products Service → handles product data
  • Orders Service → connects users and products

Each service defines its own schema, and Apollo merges them.

# Users Subgraph
type User @key(fields: "id") {
  id: ID!
  name: String
  city: String
}

Explanation:

  • type User → defines a GraphQL type
  • @key(fields: "id") → marks id as the unique identifier for federation
  • name, city → user-specific fields

Entity Resolution and @key Directive

The @key directive allows different services to reference the same entity.

type Product @key(fields: "id") {
  id: ID!
  name: String
  price: Int
}

Now suppose Orders service wants to link users and products:

type Order {
  id: ID!
  user: User
  product: Product
}

To resolve references across services, we use __resolveReference.

User: {
  __resolveReference(reference) {
    return users.find(user => user.id === reference.id);
  }
}

Explanation:

  • reference → contains entity key (id)
  • users.find(...) → fetch actual data
  • Returns full entity to the gateway

Practical Code Examples

Example 1: Building a Users Subgraph

Let’s build a simple Users service using Node.js.

// Step 1: Import dependencies
const { ApolloServer } = require('@apollo/server');
const { startStandaloneServer } = require('@apollo/server/standalone');
const { buildSubgraphSchema } = require('@apollo/subgraph');
const gql = require('graphql-tag');

// Step 2: Define schema
const typeDefs = gql`
  type User @key(fields: "id") {
    id: ID!
    name: String
    city: String
  }

  type Query {
    users: [User]
  }
`;

// Step 3: Sample data
const users = [
  { id: "1", name: "Ahmad", city: "Lahore" },
  { id: "2", name: "Fatima", city: "Karachi" }
];

// Step 4: Define resolvers
const resolvers = {
  Query: {
    users: () => users
  },
  User: {
    __resolveReference(ref) {
      return users.find(user => user.id === ref.id);
    }
  }
};

// Step 5: Create server
const server = new ApolloServer({
  schema: buildSubgraphSchema({ typeDefs, resolvers })
});

// Step 6: Start server
startStandaloneServer(server, { listen: { port: 4001 } });

Line-by-line Explanation:

  • require('@apollo/server') → imports Apollo Server
  • buildSubgraphSchema → converts schema into a federated subgraph
  • typeDefs → defines GraphQL schema
  • users → mock database
  • Query.users → returns all users
  • __resolveReference → resolves federated references
  • ApolloServer → creates server instance
  • startStandaloneServer → runs the server on port 4001

Example 2: Real-World Application (E-commerce Federation)

Let’s simulate a Pakistani e-commerce system:

// Products Subgraph
const typeDefs = gql`
  type Product @key(fields: "id") {
    id: ID!
    name: String
    price: Int
  }

  type Query {
    products: [Product]
  }
`;

const products = [
  { id: "101", name: "Laptop", price: 150000 },
  { id: "102", name: "Mobile", price: 50000 }
];

const resolvers = {
  Query: {
    products: () => products
  },
  Product: {
    __resolveReference(ref) {
      return products.find(p => p.id === ref.id);
    }
  }
};

Explanation:

  • Defines Product entity with @key
  • Stores prices in PKR (real-world relevance)
  • Resolver returns product list
  • Federation resolver connects services

Now, the Apollo Router combines services:

# router.yaml
supergraph:
  listen: 0.0.0.0:4000

Explanation:

  • supergraph.listen → defines gateway port
  • Router forwards queries to subgraphs automatically

Common Mistakes & How to Avoid Them

Mistake 1: Missing @key Directive

Problem:
Without @key, federation cannot identify entities.

type User {
  id: ID!
  name: String
}

Fix:

type User @key(fields: "id") {
  id: ID!
  name: String
}

Why it matters:
Federation needs a unique identifier to connect services.


Mistake 2: Incorrect Reference Resolver

Problem:

__resolveReference(ref) {
  return null;
}

This breaks data fetching.

Fix:

__resolveReference(ref) {
  return users.find(u => u.id === ref.id);
}

Why it matters:
If reference resolution fails, your supergraph returns incomplete data.


Practice Exercises

Exercise 1: Add Orders Service

Problem:
Create an Orders service linking Users and Products.

Solution:

type Order {
  id: ID!
  user: User
  product: Product
}
const orders = [
  { id: "5001", user: { id: "1" }, product: { id: "101" } }
];

Explanation:

  • Uses references (id) instead of full objects
  • Federation resolves actual data from other services

Exercise 2: Extend User Type

Problem:
Add email field to User from another service.

Solution:

extend type User @key(fields: "id") {
  id: ID! @external
  email: String
}

Explanation:

  • extend type → adds fields from another service
  • @external → indicates field is owned elsewhere
  • Enables modular schema design

Frequently Asked Questions

What is Apollo Federation?

Apollo Federation is a system for building a single GraphQL API from multiple microservices. It allows teams to work independently while still exposing a unified schema.

How do I connect multiple GraphQL services?

You define subgraphs with @key directives and use an Apollo Router or Gateway to compose them into a supergraph.

Is Apollo Federation better than schema stitching?

Yes, federation is more scalable and structured. It provides better tooling, type safety, and performance compared to older schema stitching methods.

Can I use Apollo Federation in small projects?

You can, but it’s most beneficial for medium to large systems. For small apps, a single GraphQL server is often simpler.

How do I deploy federated services?

Each subgraph is deployed independently (e.g., on AWS, Vercel, or local servers), while the router acts as a central entry point.


Summary & Key Takeaways

  • Apollo Federation enables scalable GraphQL microservices architecture
  • Subgraphs define independent services, combined into a supergraph
  • @key and __resolveReference are core to entity sharing
  • Apollo Router handles query planning and execution
  • Ideal for real-world apps like e-commerce, fintech, and SaaS in Pakistan
  • Encourages modular, team-friendly backend development

To deepen your understanding, explore these related tutorials on theiqra.edu.pk:

  • Learn the fundamentals in our GraphQL Tutorial for Beginners
  • Understand system design in Microservices Architecture Guide
  • Master API communication with REST vs GraphQL Comparison
  • Build scalable backends with Node.js Backend Development Tutorial

These will help you transition from beginner to advanced GraphQL developer and confidently build production-ready systems.

Practice the code examples from this tutorial
Open Compiler
Share this tutorial:

Test Your Python Knowledge!

Finished reading? Take a quick quiz to see how much you've learned from this tutorial.

Start Python Quiz

About Zaheer Ahmad