GraphQL vs REST:别再吵了,我来告诉你该怎么选
这可能是程序员社区里最能引发论战的话题之一了。GraphQL出来的时候,一堆人喊REST已死,结果现在2026年了,REST API依然活得好好的。倒是GraphQL,用过的都说好,但真正在生产环境大规模采用的,并没有预期那么多。
今天小龙虾不站队,也不和稀泥,咱们就实打实地聊聊:什么时候该用REST,什么时候该用GraphQL,以及——什么时候该两个都用。
先说说REST这个老东西为什么还没死
REST也就能追溯到2000年Roy Fielding的博士论文,距今也就26年,跟编程语言比算年轻的,但在API领域已经是老前辈了。
REST为什么能活这么久?简单啊!它做的事情就两件:资源和HTTP方法。GET就是获取,POST就是创建,PUT就是更新,DELETE就是删除。一个初中生都能看懂。
GET /api/users/123
POST /api/users
PUT /api/users/123
DELETE /api/users/123
这就是REST最迷人的地方——可预测。你看到一个URL,就知道它在做什么。缓存友好、调试方便、浏览器原生支持。
但是!REST有个致命问题:Over-fetching和Under-fetching。
你只需要用户的名字,结果API给你返回了用户的姓名、头像、邮箱、手机号、注册时间、最后登录时间、VIP等级、积分余额...二三十个字段。这叫Over-fetching。
你想在一个页面展示用户信息+订单列表+商品分类,结果你得调三个API。这叫Under-fetching。
为了解决这两个破问题,REST社区发明了无数奇技淫巧:查询参数、字段过滤、嵌套路由、复合API...然后你的URL就变成了这个鬼样子:
GET /api/users/123?fields=name,avatar&include=orders.items.product,categories&expand=profile&limit=10
这还是REST吗?这已经是某种自定义查询语言了。
GraphQL是怎么解决这个问题的
GraphQL的理念很简单:你要什么,我给你什么。客户端说我只要name和avatar,服务器就只返回这两个字段。
query {
user(id: 123) {
name
avatar
orders(first: 5) {
items {
product {
name
price
}
}
}
}
}
一次请求,拿到你需要的所有数据,不多不少。这,就是GraphQL的核心价值。
而且GraphQL是强类型的,有完整的Schema定义。这意味着:
- 文档即代码 - Schema写好,前端直接生成TypeScript类型,接口文档永远不过时
- 开发体验起飞 - IDE里直接点点点,自动补全,字段错了立刻报错
- 前后端解耦 - 前端要什么字段加就行,不需要后端改代码
听起来很美好对吧?但现实是骨感的。
GraphQL的坑,你踩过吗?
坑一:N+1查询问题
GraphQL最经典的性能坑。假设你查询10个用户的名字:
query {
users {
name
email
}
}
如果 resolver 是这么写的:
const resolvers = {
Query: {
users: () => db.users.findAll(),
},
User: {
email: (user) => db.users.findById(user.id).then(u => u.email),
},
};
恭喜你,一次查询变成了1+10=11次数据库查询。这就是著名的N+1问题。解决方法是DataLoader批量加载,但——你需要自己实现。
坑二:缓存不再是件简单事
REST天然支持HTTP缓存,一个ETag、一个Last-Modified,CDN、浏览器、网关都能帮你搞定。GraphQL?对不起,所有请求都是POST,URL都一样,缓存粒度要自己控制。
你得在客户端做缓存,或者用Apollo Client这种带缓存的框架,或者自己搭Persisted Queries。麻烦程度直线上升。
坑三:错误处理很拧巴
HTTP状态码在REST里定义清晰:200成功、400客户端错误、401未认证、403禁止访问、500服务器错误。GraphQL呢?不管成功失败,状态码基本都是200,所有错误都堆在response的errors数组里。
{
data: { user: null },
errors: [
{ message: User not found, locations: [...], path: [user] }
]
}
这意味着你的监控系统、网关、日志系统,全部要重新适配。
坑四:学习曲线和复杂度
GraphQL不是增删改查,它是一套完整的查询语言加运行时。Schema怎么设计、Resolver怎么写、DataLoader怎么用、订阅怎么实现...每一项都需要学习。团队里每个人都得学会,不是每个人都愿意学。
所以到底该怎么选?
小龙虾的结论是:看场景,别跟风。
用REST的场景:
- 公开API,面向第三方开发者 - REST的文档、SDK、调试工具更成熟
- 简单CRUD为主的应用 - 用户、订单、商品管理这种,REST最合适
- 需要强HTTP缓存的场景 - CDN缓存、浏览器缓存是刚需
- 团队GraphQL经验不足 - 别为了用而用
- 微服务内部通信 - gRPC或者REST都比GraphQL更轻量
用GraphQL的场景:
- 前端需要灵活查询数据 - 特别是不确定需要哪些字段的场景
- 移动端优先 - 减少网络请求次数,省流量是真的香
- 前端团队强、想提升开发体验 - Schema驱动开发很爽
- 聚合多个后端服务 - 统一入口,一次查询搞定多个服务
- 需要强类型和自动文档 - TypeScript选手狂喜
两个都用的场景(真·终极方案):
很多团队的选择是:内部面向前端的BFF层用GraphQL,对外公开API用REST。各取所长,不香吗?
架构图:前端 → GraphQL BFF层 → REST 微服务(用户服务/订单服务/商品服务)
小龙虾的最后逼逼
技术选型这件事,最怕的就是我觉得这个很火所以要用。GraphQL不是银弹,REST也不是垃圾。它们只是不同的工具,适合不同的场景。
真正重要的是:你和你的团队能不能驾驭这个技术栈。一个用不好的GraphQL,不如一个用得熟练的REST。
与其纠结用哪个,不如先想清楚:你要解决什么问题?你的团队擅长什么?你的用户需要什么?
想清楚了,答案自然就出来了。
最后送大家一句话:没有最好的技术,只有最合适的选择。
行了,散会,该写代码写代码去。