用途
GraphQL Architect 技能提供 GraphQL 架构方面的专业能力,专注于 schema 设计、联邦(federation)模式、resolver 优化与实时订阅。其目标是构建高性能、类型安全的 GraphQL API,并具备 N+1 查询预防、高效缓存以及跨分布式系统的可扩展 API 网关模式。
何时使用
资料列出以下适用场景:
- 为新 API 从零设计 GraphQL schema
- 跨多个服务实施 GraphQL 联邦
- 优化 resolver 以预防 N+1 查询(DataLoader 实现)
- 使用 GraphQL 订阅构建实时功能
- 从 REST 迁移到 GraphQL,或设计 REST 与 GraphQL 混合 API
- 实施 GraphQL API 网关模式
资料同时列出以下不适用场景:
- 简单 REST API 已足够(建议使用 api-designer)
- 仅做数据库 schema 设计而不涉及 API 层(建议使用 database-administrator)
- 仅做前端数据获取(建议使用 frontend-developer)
主要能力
Schema 设计
- 按最佳实践创建类型安全的 GraphQL schema
- 实现分页模式(Relay、基于 offset)
- 设计带输入校验与错误处理的 mutation
- 管理 schema 演进与向后兼容性
联邦架构
- 为微服务实施 Apollo Federation
- 配置 schema stitching 进行服务组合
- 管理跨服务的查询与 mutation
- 为 schema 组合搭建 API 网关
Resolver 优化
- 实现 DataLoader 以预防 N+1
- 在 resolver 与字段级别进行缓存策略
- 查询复杂度分析与深度限制
- 生产环境的持久化查询(persisted queries)优化
实时订阅
- 实现基于 WebSocket 的订阅
- 管理订阅生命周期与清理
- 与事件驱动后端集成
- 处理订阅的认证与授权
使用方式
资料中的快速开始列出触发本技能的时机:设计新的 GraphQL schema 或联邦架构、解决 N+1 查询性能问题、实现实时订阅、将 REST API 迁移到 GraphQL。
核心工作流:DataLoader 实现
问题:N+1 查询拖垮性能。资料给出的未使用 DataLoader 的 resolver 示例:
// WITHOUT DataLoader - N+1 problem
const resolvers = {
Post: {
author: async (post, _, { db }) => {
// Executed once per post (N+1 problem!)
return db.User.findByPk(post.userId);
}
}
};
// Query for 100 posts triggers 101 DB queries
解决方案:使用 DataLoader 批处理:
import DataLoader from 'dataloader';
// Create loader per request (important!)
function createLoaders(db) {
return {
userLoader: new DataLoader(async (userIds) => {
const users = await db.User.findAll({
where: { id: userIds }
});
// Return in same order as requested IDs
const userMap = new Map(users.map(u => [u.id, u]));
return userIds.map(id => userMap.get(id));
})
};
}
// Resolver using DataLoader
const resolvers = {
Post: {
author: (post, _, { loaders }) => {
return loaders.userLoader.load(post.userId);
}
}
};
// Same query now triggers 2 queries total!
Schema 最佳实践参考
Relay 风格分页模式:
type Query {
users(first: Int, after: String, last: Int, before: String): UserConnection!
}
type UserConnection {
edges: [UserEdge!]!
pageInfo: PageInfo!
totalCount: Int!
}
type UserEdge {
node: User!
cursor: String!
}
type PageInfo {
hasNextPage: Boolean!
hasPreviousPage: Boolean!
startCursor: String
endCursor: String
}
错误处理模式:
type Mutation {
createUser(input: CreateUserInput!): CreateUserPayload!
}
type CreateUserPayload {
user: User
errors: [UserError!]!
}
type UserError {
field: String
message: String!
code: ErrorCode!
}
enum ErrorCode {
VALIDATION_ERROR
NOT_FOUND
UNAUTHORIZED
CONFLICT
}
决策框架
GraphQL 与 REST 决策矩阵(资料以表格形式列出):
- 客户端类型:多个需求不同的客户端 → GraphQL;需求可预测的单一客户端 → REST
- 数据关系:高度嵌套、相互关联的数据 → GraphQL;关系较少的扁平资源 → REST
- 过度获取(over-fetching):客户端需要不同子集 → GraphQL;客户端通常需要全部字段 → REST
- 获取不足(under-fetching):避免多次往返 → GraphQL;单一端点已足够 → REST
- Schema 演进:频繁变更、需向后兼容 → GraphQL;API 稳定、可接受版本化 → REST
- 实时:需要订阅 → GraphQL;轮询或 webhook 已足够 → REST
Schema 设计决策树:
Schema Design Requirements
│
├─ Single service (monolith)?
│ └─ Schema-first design with single schema
│
├─ Multiple microservices?
│ ├─ Services owned by different teams?
│ │ └─ Apollo Federation
│ └─ Services owned by same team?
│ └─ Schema stitching (simpler)
│
├─ Existing REST APIs to wrap?
│ └─ GraphQL wrapper layer
│
└─ Need backward compatibility?
└─ Hybrid REST + GraphQL
N+1 预防策略:
Resolver Implementation
│
├─ Field resolves to single related entity?
│ └─ DataLoader with batching
│
├─ Field resolves to list of related entities?
│ ├─ List size always small (<10)?
│ │ └─ Direct query acceptable
│ └─ List size unbounded?
│ └─ DataLoader with batching + pagination
│
├─ Nested resolvers (users → posts → comments)?
│ └─ Multi-level DataLoaders
│
└─ Aggregations or counts?
└─ Separate DataLoader for counts
何时应升级(红旗信号)
资料列出以下需要升级的情况:
- 查询复杂度爆炸:无界嵌套查询导致 DoS
- 联邦循环依赖:schema 设计问题
- 10K+ 并发订阅:基础设施架构问题
- 跨 50+ 字段的 schema 版本化:破坏性变更管理
- 跨服务事务需求:分布式系统模式
附加资源
资料提及:
- 详细技术参考见 REFERENCE.md,含 Apollo Federation 设置工作流、字段级授权指令、查询复杂度限制
- 代码示例与模式见 EXAMPLES.md,含反模式(N+1 查询、无复杂度限制)、与其他技能的集成模式、完整 resolver 实现
以上附加资源的具体内容在本资料中暂未提供。