簡介
GraphQL Federation允許每個微服務公開一個子圖,而Router會自動將其組合成統一的超級圖。前端僅需要 1 個端點來查詢每個服務的資料。

1. 問題:多個 GraphQL 端點
❌ Mỗi service có GraphQL endpoint riêng:
Frontend → product.api.com/graphql (Product schema)
Frontend → user.api.com/graphql (User schema)
Frontend → order.api.com/graphql (Order schema)
→ Frontend phải biết endpoint nào chứa data gì
→ Không thể query cross-service trong 1 request
→ Ví dụ: Order + Product + User = 3 requests
2. GraphQL 聯邦架構
✅ Unified Supergraph:
┌─────────────┐
│ Frontend │
│ 1 endpoint │
└──────┬──────┘
│
▼
┌──────────────────────┐
│ Apollo Router │
│ (Supergraph) │
│ gateway.api.com │
└──┬────────┬────────┬─┘
│ │ │
▼ ▼ ▼
┌──────┐ ┌──────┐ ┌──────┐
│Product│ │ User │ │Order │
│Subgra│ │Subgra│ │Subgra│
│ ph │ │ ph │ │ ph │
└──────┘ └──────┘ └──────┘
1 query → Router splits → Subgraphs → Router merges → 1 response
3. 子圖定義
3.1 產品子圖
# Product Service subgraph
type Product @key(fields: "id") {
id: ID!
name: String!
price: Float!
description: String
category: Category!
}
type Category {
id: ID!
name: String!
}
type Query {
product(id: ID!): Product
products(limit: Int, offset: Int): [Product!]!
}
3.2 回顧子圖(擴展產品)
# Review Service subgraph — extends Product
type Product @key(fields: "id") {
id: ID!
reviews: [Review!]!
averageRating: Float
}
type Review {
id: ID!
rating: Int!
comment: String
author: User!
}
type Query {
reviews(productId: ID!): [Review!]!
}
3.3 聯合查詢
# Frontend query — Router handles cross-service resolution
query ProductPage($id: ID!) {
product(id: $id) {
id # → Product Subgraph
name # → Product Subgraph
price # → Product Subgraph
reviews { # → Review Subgraph
rating
comment
author { # → User Subgraph
name
avatar
}
}
averageRating # → Review Subgraph
}
}
自動路由器: 1.查詢產品子圖→取得產品數據 2.查詢評論子圖→取得評論(使用product.id) 3.查詢使用者子圖→取得作者資訊(使用review.author.id) 4. 合併全部→回傳1個回應
4. 模式拼接與聯合
| 模式拼接 | 聯合會 | |
|---|---|---|
| 所有權 | 網關擁有架構 | 服務自己的架構 |
| 聯軸器 | 高(網關了解服務) | 低(服務聲明本身) |
| 可擴充性 | 網關瓶頸 | 分散式 |
| 進化 | 硬(中心變化) | 簡單(服務等級) |
| 判決 | ❌ 遺產 | ✅ 推薦 |
5. 效能注意事項
5.1 查詢計劃最佳化
Router tạo query plan tối ưu:
─ Parallel: Product + User subgraphs (independent)
─ Sequential: Reviews → after Product (needs product.id)
5.2 資料載入器模式
// Trong Review Subgraph, batch user lookups
const userLoader = new DataLoader(async (userIds) => {
const users = await userService.getUsers(userIds);
return userIds.map(id => users.find(u => u.id === id));
});
// Resolve author field
Review: {
author: (review) => userLoader.load(review.authorId)
}
5.3 快取
Persisted Queries: Client gửi query hash thay vì full query
Automatic Persisted Queries (APQ): Router cache query plans
CDN caching: @cacheControl directive
6. 何時使用聯邦?
✅ Dùng khi:
- Nhiều microservices cần unified GraphQL API
- Frontend teams muốn 1 endpoint
- Complex, nested data relationships
- Multiple frontend clients
❌ Không cần khi:
- Chỉ có 1-2 services (đơn giản quá)
- REST đã đủ tốt
- Team chưa quen GraphQL
- Performance-critical (thêm latency qua Router)
總結
- 聯邦 = 每個服務都有自己的子圖,Router組成超圖
@key跨子圖的實體引用指令- 路由器自動分割、解析、合併查詢
- DataLoader 模式避免了 N+1 問題
- 當您需要統一的 GraphQL API 用於多種服務時使用
下一篇文章: 第 20 課:測試微服務 — 單元、整合與 E2E