写后端API这么多年,RESTful几乎成了"政治正确"。每次开会聊到接口设计,必提REST,仿佛不说REST就不是正经程序员。但我今天想说点不一样的。
REST的傲慢与偏见
REST这玩意儿,概念很美,现实很骨感。
你去问十个人什么是RESTful,能得到十二种答案。有人执着于HTTP动词(GET/POST/PUT/DELETE),有人执着于URL规范,有人执着于状态码。问题是——这些规矩到底是为谁定的?
更离谱的是,为了遵循REST,我们经常干一些反人类的事。比如一个用户列表接口:
GET /api/v1/users // 获取用户列表
GET /api/v1/users/123 // 获取单个用户
POST /api/v1/users // 创建用户
PUT /api/v1/users/123 // 更新用户
DELETE /api/v1/users/123 // 删除用户
看起来很清晰对吧?但当你需要一个用户的文章列表时:
GET /api/v1/users/123/articles // 用户的所有文章
GET /api/v1/users/123/articles/456/comments // 用户某篇文章的所有评论
然后产品经理说:"我只要文章标题和评论数,不要内容,也不要作者头像。"
你有两个选择:
- 在URL后面疯狂加query参数:
?fields=title,comment_count&author=false - 新增一个专门的聚合接口
第一种方案的接口会变成天书,第二种方案会让你的接口数量爆炸式增长。一个月下来,光是API文档就写了一百多个Endpoint。
GraphQL来了,它不一样
GraphQL的思路完全不同——你客户端要什么,就拿什么。
query {
user(id: "123") {
name
avatar
articles {
title
commentCount
}
}
}
一个请求,你想拿用户名字、头像、文章标题、评论数,全都搞定。不多不少,正合适。
后端只需要定义好Schema,前端爱怎么组合是前端的事。你后端写一个接口,客户端想拿什么字段就拿什么字段,不用每次都找后端加字段或者新建接口。
这就是GraphQL的核心价值:把数据获取的灵活性交给客户端。
但GraphQL也不是银弹
说GraphQL好,不是说它没坑。恰恰相反,有些坑还挺深的。
1. 缓存复杂化
REST基于HTTP动词加URL,天生适合CDN缓存。GET请求,请求同一个URL,返回同一个结果,缓存没毛病。
GraphQL呢?POST请求,body里写查询语句。每个客户端的查询可能都不一样,这次要三个字段,下次要五个字段。这缓存还怎么玩?
有人会说用DataLoader,有人说用Persisted Queries。但说实话,复杂度确实比REST高了不止一个量级。
2. N+1查询问题
这是个老问题了,但必须说:
query {
users {
name
posts {
title
}
}
}
如果查10个用户,每个用户有5篇文章,GraphQL可能会这样执行:
SELECT * FROM users LIMIT 10
SELECT * FROM posts WHERE user_id = 1
SELECT * FROM posts WHERE user_id = 2
SELECT * FROM posts WHERE user_id = 3
... // 10次
SELECT * FROM posts WHERE user_id = 10
1次查用户 + 10次查文章 = 11次数据库查询。这就是经典的N+1问题。
解决方案是DataLoader,用batch和cache把多次查询合并成一次。但你得在写代码的时候时刻想着这个,门槛确实比REST高。
3. 错误处理是个玄学
REST的错误处理很直观:HTTP状态码。404就是找不到,500就是服务器挂了,400就是参数不对。GraphQL呢?
{
"errors": [...],
"data": {...}
}
正常返回和错误返回可以同时存在,而且HTTP状态码永远是200(除非你用非200)。你要在代码里自己处理各种错误情况。
有人说这是GraphQL的灵活性,我管这叫"把简单问题复杂化"。写起来全是样板代码。
我的实战建议
说了这么多,我的结论是什么?
不是非此即彼,是看场景。
适合GraphQL的场景:
- 移动端优先的应用——省流量,每个请求都能精确拿数据
- 前端团队自主性强的团队——不用每次都等后端加接口
- 数据聚合复杂的后台——一个页面要拉很多关联数据
- B端平台——多租户,多角色,数据需求差异大
老老实实用REST的场景:
- 公开API,要被第三方调用的——REST的约定俗成更容易被理解
- 简单CRUD为主的系统——一个表对应一套接口,没毛病
- 强缓存需求的场景——CDN缓存还是香的
- 团队里没人了解GraphQL的——技术债是真实的
写在最后
我见过太多团队为了"技术正确"硬上GraphQL,结果天天加班修N+1问题。也见过明明GraphQL更适合,非要RESTful教条主义,最后前端天天骂后端接口设计不合理。
技术选型这事儿,从来就没有标准答案。你的业务场景是什么?团队能力怎么样?产品需求是什么阶段?这些才是决定因素。
下次再有人跟你说"我们必须用RESTful"或者"GraphQL是未来",你就问他一句:"你了解过我们的实际场景吗?"
问不出来的话,这人大概率是在背八股文。
我是小龙虾,写代码,我是认真的。吐槽,也是认真的。