GraphQL Federation for Microservices Unification

Our company is engaged in the development, support and maintenance of sites of any complexity. From simple one-page sites to large-scale cluster systems built on micro services. Experience of developers is confirmed by certificates from vendors.
Development and maintenance of all types of websites:
Informational websites or web applications
Business card websites, landing pages, corporate websites, online catalogs, quizzes, promo websites, blogs, news resources, informational portals, forums, aggregators
E-commerce websites or web applications
Online stores, B2B portals, marketplaces, online exchanges, cashback websites, exchanges, dropshipping platforms, product parsers
Business process management web applications
CRM systems, ERP systems, corporate portals, production management systems, information parsers
Electronic service websites or web applications
Classified ads platforms, online schools, online cinemas, website builders, portals for electronic services, video hosting platforms, thematic portals

These are just some of the technical types of websites we work with, and each of them can have its own specific features and functionality, as well as be customized to meet the specific needs and goals of the client.

Our competencies:
Development stages
Latest works
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1161
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1041
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    822
  • image_crm_chasseurs_493_0.webp
    CRM development for Chasseurs
    847
  • image_website-sbh_0.png
    Website development for SBH Partners
    999
  • image_website-_0.png
    Website development for Red Pear
    451

Implementing GraphQL Federation for Microservices Integration

GraphQL Federation enables building a unified data graph from multiple independent GraphQL services. A client makes a single request to the Federation Gateway, which assembles data from different subgraph services and returns a unified response. Each team owns its subgraph and deploys independently.

Federation Architecture

Client (browser/mobile)
        │
        ▼
  Federation Gateway (Apollo Router / Apollo Gateway)
        │
   ┌────┴────┬──────────┬──────────┐
   ▼         ▼          ▼          ▼
User        Order      Product   Review
Subgraph   Subgraph   Subgraph  Subgraph
(Node.js)  (Go)       (Python)  (Node.js)
   │         │          │
Postgres   Postgres   MongoDB

Subgraph: User Service

// user-service/schema.ts
import { buildSubgraphSchema } from '@apollo/subgraph';
import { gql } from 'graphql-tag';

const typeDefs = gql`
  extend schema
    @link(url: "https://specs.apollo.dev/federation/v2.3",
          import: ["@key", "@shareable"])

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

  type Query {
    me: User
    user(id: ID!): User
  }
`;

const resolvers = {
  User: {
    // Reference resolver — allows other services to extend User
    __resolveReference: async ({ id }) => {
      return userRepository.findById(id);
    }
  },
  Query: {
    me: (_, __, { userId }) => userRepository.findById(userId),
    user: (_, { id }) => userRepository.findById(id)
  }
};

export const schema = buildSubgraphSchema({ typeDefs, resolvers });

Subgraph: Order Service — Extending User Type

// order-service/schema.ts
const typeDefs = gql`
  extend schema
    @link(url: "https://specs.apollo.dev/federation/v2.3",
          import: ["@key", "@external", "@requires"])

  type Order @key(fields: "id") {
    id: ID!
    status: OrderStatus!
    total: Float!
    items: [OrderItem!]!
    customer: User!    # reference to type from User subgraph
    createdAt: DateTime!
  }

  # Extend User type from another subgraph
  type User @key(fields: "id") {
    id: ID! @external  # field belongs to User subgraph
    orders(limit: Int = 10): [Order!]!
    orderStats: OrderStats!
  }

  type OrderStats {
    totalOrders: Int!
    totalSpent: Float!
    lastOrderAt: DateTime
  }

  enum OrderStatus { PENDING PAID SHIPPED DELIVERED CANCELLED }

  type Query {
    order(id: ID!): Order
    orders(customerId: ID, status: OrderStatus): [Order!]!
  }
`;

const resolvers = {
  User: {
    __resolveReference: async ({ id }) => ({ id }),  // stub for @external fields
    orders: async ({ id }, { limit }) =>
      orderRepository.findByCustomerId(id, limit),
    orderStats: async ({ id }) =>
      orderRepository.getStatsForCustomer(id)
  },
  Order: {
    __resolveReference: async ({ id }) => orderRepository.findById(id),
    customer: ({ customerId }) => ({ __typename: 'User', id: customerId })
  }
};

Apollo Router (Federation Gateway)

# router.yaml
federation_version: 2.3

supergraph:
  listen: 0.0.0.0:4000

subgraphs:
  users:
    routing_url: http://user-service:4001/graphql
  orders:
    routing_url: http://order-service:4002/graphql
  products:
    routing_url: http://product-service:4003/graphql

cors:
  origins:
    - https://app.example.com

headers:
  all:
    request:
      - propagate:
          named: Authorization
      - propagate:
          named: X-Correlation-Id
# Run via Docker
docker run -p 4000:4000 \
  -v $(pwd)/router.yaml:/dist/config/router.yaml \
  -e APOLLO_KEY=service:my-graph:xxx \
  -e APOLLO_GRAPH_REF=my-graph@production \
  ghcr.io/apollographql/router:latest

Client Query through Federation

The client writes a query as if it's a unified graph:

query GetUserDashboard($userId: ID!) {
  user(id: $userId) {
    name
    email
    orders(limit: 5) {      # data from Order subgraph
      id
      status
      total
      items {
        product {           # data from Product subgraph
          name
          imageUrl
        }
        quantity
      }
    }
    orderStats {
      totalOrders
      totalSpent
    }
  }
}

The Router automatically builds an execution plan: fetch user from User subgraph, then parallelize requests to Order subgraph and data enrichment.

Managed Federation (Apollo Studio)

With Managed Federation, subgraph schemas are published to Apollo Studio Registry:

# In CI/CD pipeline
rover subgraph publish my-graph@production \
  --schema ./schema.graphql \
  --name orders \
  --routing-url http://order-service:4002/graphql

The Router loads the current supergraph schema automatically when any subgraph changes. Publishing includes compatibility checks via rover subgraph check.

Authorization at Subgraph Level

const resolvers = {
  Order: {
    // Only owner or admin sees order details
    __resolveReference: async ({ id }, { user }) => {
      const order = await orderRepository.findById(id);
      if (!order) return null;
      if (order.customerId !== user.id && !user.roles.includes('admin')) {
        throw new ForbiddenError('Access denied');
      }
      return order;
    }
  }
};

Implementation Timeline

  • 2–3 subgraphs with basic Federation — 2–3 weeks
  • Apollo Router + Managed Federation + CI compatibility checks — an additional week
  • Complex @requires, @provides, nested resolvers — 1–2 additional weeks