RESTful API 在大多数场景下足够好,但当你面对一个需要聚合多个数据源、且前端每次需要的字段组合都不一样的复杂应用时,GraphQL 提供了更优雅的解决方案。

GraphQL 的核心优势

问题 REST GraphQL
过度获取 返回整个对象,很多字段没用 客户端指定需要的字段
获取不足 需要多次请求不同端点 一次请求获取所有关联数据
版本管理 /v1/users, /v2/users 通过 Schema 演进,无需版本号
文档 Swagger 手动维护 自省系统自动生成

Schema 定义

GraphQL Schema 是 API 的契约——定义了所有可用的类型、查询和变更:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
type User {
id: ID!
name: String!
email: String
posts: [Post!]
}

type Query {
user(id: ID!): User
users(limit: Int = 10): [User!]!
}

type Mutation {
createUser(name: String!, email: String!): User!
}

N+1 问题与 DataLoader

GraphQL 最常见的性能陷阱——当查询嵌套关系时,Resolver 会为每个父对象单独查询一次子对象。100 个用户 = 1 次查用户 + 100 次查帖子 = 101 次查询。

DataLoader 通过批处理和缓存解决这个问题:

它会把同一个事件循环内的多次数据库查询合并为单次批量查询,并且同一请求内相同 key 只查一次。101 次查询就被压缩到了 2 次。

安全防护

GraphQL 的灵活性也带来了安全隐患——恶意客户端可以构造深度嵌套的查询导致服务端崩溃。

防护措施:限制查询深度(禁止超过 5 层嵌套)、查询复杂度分析(给每个字段设定成本值,超过阈值拒绝执行)、超时机制(为每个查询设定最大执行时间)。

REST vs GraphQL 选型建议

场景 推荐
简单的 CRUD API REST
移动端/前端多样化的数据需求 GraphQL
微服务间通信 REST(gRPC 更好)
需要实时订阅 GraphQL Subscriptions
需要 CDN 缓存 REST
多个异构数据源聚合 GraphQL

总结

GraphQL 不是 REST 的替代品,而是另一种工具。REST 简单可靠,适合大多数场景。GraphQL 在前端需要灵活数据组装时展现出强大的适配能力。关键在于——用正确的工具解决正确的问题。