7.8 KiB
7.8 KiB
id, title, category, status, source_trust_level, verification_status, created_at, updated_at, tags, tech_stack, applied_in, aliases
| id | title | category | status | source_trust_level | verification_status | created_at | updated_at | tags | tech_stack | applied_in | aliases | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| backend-graphql-federation | GraphQL Federation — Apollo / Mesh / Hive | Coding | draft | B | conceptual | 2026-05-09 | 2026-05-09 |
|
|
|
GraphQL Federation
Microservice 가 GraphQL = federation. Subgraph (per service) → Supergraph (gateway). Apollo Federation 가 표준. 작은 system 가 stitching.
📖 핵심 개념
- 매 service 가 own schema (subgraph).
- Gateway 가 query plan + 분산 실행.
- Entity (cross-service type).
- Schema composition.
💻 코드 패턴
Federation 식
# users service (subgraph)
type User @key(fields: "id") {
id: ID!
email: String!
}
# orders service (subgraph)
type Order {
id: ID!
total: Float!
user: User! # users service 의 User
}
extend type User @key(fields: "id") {
id: ID! @external
orders: [Order!]! # orders 가 추가
}
→ User 가 두 service 가 정의 (federated).
Apollo Server (subgraph)
import { ApolloServer } from '@apollo/server';
import { buildSubgraphSchema } from '@apollo/subgraph';
const typeDefs = `
type User @key(fields: "id") {
id: ID!
email: String!
}
type Query {
users: [User!]!
}
`;
const resolvers = {
Query: { users: () => db.users.find() },
User: {
__resolveReference: ({ id }) => db.users.findOne({ id }),
},
};
const server = new ApolloServer({
schema: buildSubgraphSchema({ typeDefs, resolvers }),
});
→ __resolveReference 가 다른 service 가 reference.
Apollo Router (gateway)
# router.yaml
supergraph:
listen: 0.0.0.0:4000
subgraphs:
users:
routing_url: http://users:4001
orders:
routing_url: http://orders:4002
router --config router.yaml
→ Single endpoint, query 가 자동 분산.
Supergraph composition
# Compose subgraph schemas → supergraph
rover supergraph compose --config supergraph.yaml > supergraph.graphql
# supergraph.yaml
subgraphs:
users:
routing_url: http://users:4001
schema:
file: users/schema.graphql
orders:
routing_url: http://orders:4002
schema:
file: orders/schema.graphql
Apollo Studio / Hive
Schema registry:
- 매 service 가 schema publish.
- Compose 가 검증.
- Breaking change 감지.
- Performance 가 visualize.
→ Apollo Studio (paid).
Hive (open source, free).
Entity resolution
query {
orders {
id
user {
email # users service 가
}
}
}
Gateway 가:
1. orders service: orders + user.id 가져옴.
2. users service: User(id: ...) batch.
3. Merge.
→ N+1 자동 batch (DataLoader).
Federation directives
@key(fields: "id") # Entity (cross-service)
@external # Field 가 다른 service 가
@requires(fields: "stock") # 다른 service field 필요
@provides(fields: "name") # 이 service 가 줌
@shareable # 여러 service 가 정의 OK
@override(from: "old-service") # Migration
@inaccessible # Public 안 보임
GraphQL Mesh
# mesh.yaml
sources:
- name: users
handler:
openapi:
source: https://users/openapi.json
- name: orders
handler:
graphql:
endpoint: https://orders/graphql
→ 매 source (REST, GraphQL, gRPC) 가 unified GraphQL.
→ Apollo Federation 가 GraphQL only. Mesh 가 다양.
Schema stitching (legacy)
import { stitchSchemas } from '@graphql-tools/stitch';
const schema = stitchSchemas({
subschemas: [usersSchema, ordersSchema],
});
→ Federation 의 옛 version. 작은 use case.
Performance: query plan
query {
user(id: 1) {
name
orders {
total
product {
name
}
}
}
}
Plan:
1. users service: user(id: 1) → {id, name}.
2. orders service: orders for user.id 1 → [{id, total, productId}].
3. products service: products([1, 2, 3]) batch → [{id, name}].
→ 3 service 호출, parallel where possible.
N+1 방지 (DataLoader)
import DataLoader from 'dataloader';
const userLoader = new DataLoader(async (ids: string[]) => {
const users = await db.users.find({ id: { $in: ids } });
return ids.map(id => users.find(u => u.id === id));
});
// Resolver
User: { id: ({ id }) => userLoader.load(id) }
→ 매 request 가 자체 loader. Batch.
Authentication
// Gateway 가 auth header forward
const router = new Router({
subgraphs: {
users: { routing_url: '...', willSendRequest: ({ request }) => {
request.http.headers.set('user-id', context.userId);
}},
},
});
// Subgraph 가 user-id header 사용
Rate limit
Gateway level (Apollo Router):
- Query depth limit (5).
- Query complexity limit (1000 cost).
- Per-user rate.
Subgraph level:
- Per-resolver rate.
Caching
Apollo Router:
- Response cache.
- Per-field hint (@cacheControl).
- CDN cache.
Subgraph:
- DataLoader (per-request).
- Redis (per-field).
type User @cacheControl(maxAge: 300) {
id: ID!
email: String! @cacheControl(maxAge: 60)
}
Tracing
- Apollo Studio: query timing.
- OpenTelemetry: span 별 service.
- Prometheus: metric.
→ "이 query 가 어디 서비스 가 느림?" visible.
Schema linting
# Apollo Rover
rover graph check my-graph@current --schema schema.graphql
→ Breaking change 감지.
Versioning
GraphQL = no version (single schema 가 evolve).
- Add fields: OK.
- Remove field: deprecated → grace period → remove.
- Rename: 새 field + 옛 deprecated.
→ Mobile app 가 옛 client 도 작동.
Federation 의 alternative
- BFF (Backend for Frontend): per-client REST + GraphQL.
- API Gateway (REST): 단순.
- gRPC + Buf: type-safe.
- tRPC: TS-only.
→ GraphQL Federation 가 큰 system + 다양 client.
When NOT?
- 작은 system (1-2 service): 직접 GraphQL.
- Single client: REST 충분.
- 매우 high-throughput: gRPC.
- Mobile-only + simple: tRPC / REST.
Migration
1. 1 monolith GraphQL.
2. 1 service split → subgraph.
3. Gateway 추가 (federation 활성).
4. 점진 split.
5. 옛 monolith retire.
→ Strangler fig.
Production
- Apollo Router (Rust, 빠름).
- Hive (open source registry).
- Mesh (REST → GraphQL).
- ko / pothos / Yoga / Mercurius (subgraph servers).
Cost / overhead
Federation 가 큰 cost:
- Gateway latency (10-50ms).
- Schema composition complexity.
- 매 service 가 federation aware.
→ 5+ service GraphQL 가 sweet spot.
Real-world
- Netflix: 큰 GraphQL Federation.
- Airbnb: federation 사용.
- Expedia: federation.
- Walmart: 큰 multi-team.
- Atlassian: federation 마이그레이션.
🤔 의사결정 기준
| 상황 | 추천 |
|---|---|
| 단일 GraphQL | 직접 server |
| 5+ subgraph | Apollo Federation |
| Mixed source | GraphQL Mesh |
| 작은 (legacy) | Schema stitching |
| Schema registry | Apollo Studio / Hive |
| 빠른 gateway | Apollo Router (Rust) |
| Simple TS RPC | tRPC |
❌ 안티패턴
- 모든 거 federation (작은 system): 큰 overhead.
- No DataLoader: N+1 폭발.
- Schema 무계획 변경: client 깨짐.
- No cache: latency.
- Auth gateway 만: subgraph 도 검증.
- No tracing: bottleneck 모름.
- Subgraph 가 cross-service join: federation 의 가치 ↓.
🤖 LLM 활용 힌트
- Federation = supergraph + subgraph + entity.
- Apollo Router 가 빠름 (Rust).
- Hive 가 open source registry.
- DataLoader 가 N+1 의 답.