GraphQL
GraphQL 是一种面向 API 的强类型查询语言与执行模型:服务端公开 Schema,客户端按需声明字段,由 Resolver 把查询映射到真实业务数据。
[!info] related notes
- 所属 MOC: graphql-moc
- 历史与生态: graphql-history-and-adoption
- 完整案例: graphql-end-to-end-request-flow
- 对比: graphql-vs-rest
GraphQL
一句话定义
GraphQL 让客户端描述“这次具体需要什么数据”,服务端则用一套强类型 Schema 约束可查询范围,并通过 Resolver 执行查询。
它不是数据库,也不是前端状态库;它是一种 API 查询语言、类型系统与服务端执行模型。
它和 REST 是同一种东西吗
可以把 GraphQL 和 REST 放在同一个“API 设计选型”问题里比较,但严格来说它们不是完全相同类别:
REST
= 一种 API / 分布式系统架构风格
强调 resource、URI、HTTP method、无状态等约束
GraphQL
= 一套正式规范
包含 query language、type system、validation、execution、introspection
所以“GraphQL 类似 RESTful 的接口方案”这个理解作为入门比较是对的,但 GraphQL 的规范比“接口命名风格”更具体:它直接定义了请求语言和服务端怎样校验、执行这棵查询树。
GraphQL 常运行在 HTTP 之上,例如 POST /graphql,但 GraphQL 本身不是 HTTP 的替代品。
它想解决什么问题
REST 常把数据能力拆成多个 endpoint:
GET /users/u1
GET /users/u1/training-plan
GET /users/u1/latest-diagnosis
如果一个页面恰好需要三者,客户端可能要发多次请求;如果某个 endpoint 返回字段过多,又会出现 over-fetching。
GraphQL 改成让客户端声明字段:
query {
user(id: "u1") {
name
currentTrainingPlan { title }
latestDiagnosis { summary }
}
}
服务端只允许查询 Schema 中公开的字段。
核心工作模型
Schema
↓ 定义可查询能力
Query / Mutation / Subscription
↓ 描述一次操作
Resolver / API Adapter
↓
Service / Policy
↓
Repository / Database / Other APIs
↓
GraphQL Response
真正值得掌握的不是语法,而是这几个边界:
- Schema:API 契约;
- Query:读取;
- Mutation:显式写操作;
- Subscription:持续接收服务端事件;
- Resolver:把字段映射到真实业务实现,通常作为 GraphQL Adapter 而不是业务层;
- Context:携带本次 request 的可信身份与 request-scoped 依赖;
- DataLoader:把同一 request 内重复字段加载批量化并去重;
- Client Cache:客户端如何保存、合并和更新 GraphQL 数据。
一个关键特征:查询形状接近响应形状
query {
user(id: "u1") {
name
profile { height }
}
}
响应通常沿相同结构返回:
{
"data": {
"user": {
"name": "Sean",
"profile": { "height": 175 }
}
}
}
这让客户端能明确控制当前视图真正依赖的字段。
这里的“自由查询”有明确边界:客户端只能在 Schema 已公开的字段和关系中组合,不能直接写 SQL,也不能绕过 Resolver / Authorization 随便访问服务端数据。
Query、Mutation 与 Subscription 是三种不同同步语义
Query
→ 主动读取当前服务端状态
Mutation
→ 当前客户端主动请求改变服务端状态
Subscription
→ 当前客户端持续接收服务端之后发生的外部变化
Mutation 与 Subscription 不应该混为一谈:当前客户端自己执行 Mutation,且响应已经返回足够的更新实体时,Apollo Client 通常可以据此更新本地 normalized cache;另一个用户、设备、后台任务或服务引发的变化,则需要 Subscription、轮询、SSE/WebSocket event 或 refetch 等机制让当前客户端先“知道变化发生了”。
GraphQL 带来的新成本
GraphQL 并不是“更高级的 REST”。灵活查询同时把一些复杂度转移到了新的位置:
- Schema 设计与演进;
- Resolver / Service 授权;
- 查询复杂度与深度控制;
- N+1 数据库查询与 DataLoader;
- 客户端 normalized cache;
- Mutation 后 cache reconciliation;
- GraphQL 错误与部分成功语义;
- Subscription 的连接、跨实例传播与恢复。
什么时候值得考虑
GraphQL 更适合:客户端数据组合复杂、多个客户端字段需求差异大、关系图丰富且团队愿意治理 Schema/Resolver/Cache 的系统。
简单 CRUD、文件传输、天然 HTTP 资源语义明显,或团队并不需要客户端自由选字段时,REST 往往更直接。
学习时最重要的判断
不要问“GraphQL 是否比 REST 好”,而要问:
它把什么复杂度从 endpoint/DTO 转移到了 Schema、Resolver、执行治理和 Client Cache?这种交换在当前系统里值不值得?