Реалізація GraphQL Federation для об'єднання мікросервісів
Уявіть: фронтенд-команда витрачає години на координацію з бекендерами, щоб зібрати одну сторінку. Кожен мікросервіс віддає дані у своєму форматі — доводиться робити 5–10 запитів до різних API. Виникають N+1 проблеми, latency зростає, кешування перетворюється на головний біль. На одному з проєктів ми скоротили кількість запитів з 12 до 2, впровадивши Federation. Наш досвід — 7+ років у розподілених системах, понад 50 продакшен-впроваджень GraphQL. Федерація — це не просто gateway, а декларативний підхід: кожна команда описує, як її мікросервіс розширює загальний граф даних. На відміну від ручного агрегування, Federation автоматично будує оптимальний план виконання, використовуючи @key та @requires.
Як об'єднати мікросервіси за допомогою GraphQL Federation?
Federation дозволяє об'єднати декілька незалежних GraphQL-сервісів (subgraph) в єдиний API. Клієнт робить один запит до Federation Gateway (Apollo Router), який збирає дані з різних subgraph і повертає єдину відповідь. Кожна команда володіє своїм subgraph і деплоїть його незалежно — без блокувань і узгоджень. Детальна специфікація доступна в документації Apollo Federation.
Архітектура Federation:
- Клієнт (браузер/мобільний) → Federation Gateway (Apollo Router / Apollo Gateway)
- User Subgraph (Node.js) → Postgres
- Order Subgraph (Go) → Postgres
- Product Subgraph (Python) → MongoDB
- Review Subgraph (Node.js) → Postgres
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: {
__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 — розширення типів
// 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!
createdAt: DateTime!
}
type User @key(fields: "id") {
id: ID! @external
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 }),
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
Запуск через 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.
Що дає Federation порівняно з REST і звичайним Gateway?
| Характеристика | Federation | REST-агрегатор | Звичайний Gateway |
|---|---|---|---|
| Кількість запитів | 1 | 5–10 | 1 (але дані збираються послідовно) |
| Час відповіді | ~50 мс (паралельні запити) | ~200 мс | ~100–150 мс (послідовно) |
| Незалежність команд | ✅ Кожна команда володіє subgraph | ❌ Спільна кодова база | ❌ Спільна кодова база |
| Зміна схеми | Без блокувань | Узгодження | Узгодження |
| Кешування | На рівні subgraph | HTTP-кеш | Централізоване |
Federation дозволяє підвищити продуктивність у 2–3 рази порівняно з REST-агрегатором за рахунок паралельної вибірки та кешування на рівні subgraph. На одному проєкті ми знизили час завантаження сторінки з 2.3 до 0.8 секунди — це в 2.9 рази швидше.
| Інструмент | Призначення | Розповсюдження |
|---|---|---|
| Apollo Router | Federation Gateway, паралельний збір даних | Open source + Managed Apollo |
| Rover CLI | Публікація та перевірка схем | Open source |
| Apollo Studio | Реєстр схем, моніторинг | SaaS |
Managed Federation (Apollo Studio)
При Managed Federation схеми subgraph публікуються в Apollo Studio Registry. Router завантажує актуальну supergraph-схему автоматично при зміні будь-якого subgraph. Публікація з перевіркою сумісності виконується через rover subgraph check.
# В CI/CD пайплайні
rover subgraph publish my-graph@production \
--schema ./schema.graphql \
--name orders \
--routing-url http://order-service:4002/graphql
Авторизація на рівні subgraph
Кожен subgraph самостійно перевіряє права. Приклад на TypeScript: в ресолвері Order __resolveReference перевіряється, що поточний користувач — власник замовлення або має роль admin. У разі відмови повертається помилка ForbiddenError.
Чому Federation варто обрати для нового проєкту?
Federation дає незалежність командам, атомарні деплої та автоматичну перевірку сумісності. Ми гарантуємо, що схема залишиться консистентною при кожній зміні. Це найкраще рішення для компаній з 3+ мікросервісами, де важлива швидкість змін.
Що входить в роботу?
- Аудит поточної архітектури та виділення меж subgraph.
- Проектування supergraph-схеми з @key та @requires.
- Реалізація subgraph-сервісів (Node.js, Go, Python — будь-який стек).
- Налаштування Apollo Router з CORS, авторизацією, моніторингом.
- Інтеграція Managed Federation з CI-пайплайном перевірки сумісності.
- Документація по схемі та точках розширення.
- Навчання команди роботі з Federation.
- Підтримка на старті: 2 тижні після запуску.
Процес роботи та терміни
- Аналіз — виділяємо межі subgraph, визначаємо точки інтеграції з legacy.
- Проектування — описуємо supergraph-схему, узгоджуємо @key та @requires.
- Розробка — кожен subgraph створюється як окремий сервіс з власним деплоєм.
- Налаштування Router — конфігурація CORS, авторизації, моніторингу (Apollo Studio).
- Managed Federation — підключаємо CI-пайплайн з перевіркою сумісності.
- Тестування — навантажувальне тестування та E2E-тести.
- Запуск — покроковий rollout з моніторингом помилок.
Терміни реалізації:
- 2–3 subgraph з базовою Federation — 2–3 тижні.
- Apollo Router + Managed Federation + CI-перевірки сумісності — ще 1 тиждень.
- Складні @requires, @provides, nested resolvers — 1–2 додаткові тижні.
Вартість розраховується індивідуально після аналізу вашого проєкту. Орієнтовний бюджет від $5000 для базового впровадження. Отримайте консультацію — ми оцінимо обсяг роботи і запропонуємо оптимальне рішення. Команда має 7+ років досвіду та виконала 50+ проєктів. Замовте впровадження Federation: зв'яжіться з нами — підготуємо пропозицію під ключ. Ваша архітектура стане гнучкою та масштабованою без зайвих витрат.
Приклад детальної реалізації subgraph на TypeScript
Весь код User та Order subgraph доступний у репозиторії. При необхідності адаптуємо під ваш стек.Отримайте консультацію по впровадженню Federation — напишіть нам, і ми оцінимо ваш проєкт.







