API 设计的两个误区:RESTful 和 GraphQL 都不是银弹

前两天团队讨论新业务的技术方案,后端同学提议用 GraphQL,理由是"前端可以自己控制数据结构,不用频繁改接口"。我问了一句:"你们后端有多少人?"答:"3个人"。我说:"那别折腾了,RESTful 就够了"。

这不是第一次遇到这种情况。这些年做全栈,从后端写 API 到前端调 API 再到 BFF 层设计 API,见过太多技术选型上的执念。最常见的两个误区:一是觉得 RESTful 就是正统,必须符合所有规范;二是觉得 GraphQL 能解决前后端协作的所有问题。

事实上,这两个都不是银弹。

 

RESTful 的形式主义陷阱

 

大部分开发者第一次接触 API 设计,学的都是 RESTful 规范。GET 查询、POST 创建、PUT 更新、DELETE 删除,资源路径用名词不用动词,状态码要严格遵循 HTTP 标准。这些原则没错,但问题在于,很多人把它当成了教条。

我见过一个场景:产品要求做一个"一键清空购物车"的功能。后端同学纠结了半天,说"清空"是个动作,不符合 RESTful 原则,最后设计成了 `DELETE /api/cart/items?all=true`。前端调用时发现,这个接口不仅清空了购物车,还要返回一个确认弹窗,展示清空了多少商品、节省了多少存储空间。结果又加了一个 `GET /api/cart/clear-preview` 接口来获取这些信息。

这就是典型的为了 RESTful 而 RESTful。实际上,如果直接设计成 `POST /api/cart/clear`,一次性返回清空结果和统计信息,前端一个请求就能搞定,代码更清晰,性能也更好。

RESTful 的核心价值不是资源路径的命名规范,而是让 API 的行为可预测。如果为了符合规范而让接口变得反直觉,那就是本末倒置了。

在金融业务中,这种情况更常见。比如"赎回理财产品"这个操作,涉及资产冻结、资金计算、风控校验、短信通知等一系列动作,很难用简单的 POST/PUT 来描述。如果硬要套 RESTful,接口可能要设计成 `POST /api/assets/{id}/redemption`,但实际上前端需要的是一个明确的"赎回"动作,而不是对某个资源的修改。这时候,`POST /api/redeem` 或者 `POST /api/assets/redeem` 反而更直观。

我的观点是:RESTful 是一个好的设计原则,但不是必须遵守的法律。当业务逻辑和 RESTful 规范冲突时,优先考虑业务的直观性和开发效率,而不是死守规范。

 

GraphQL 的协作成本被低估了

 

GraphQL 这几年很火,尤其是在前端社区。很多人觉得它能解决前后端协作的痛点:前端需要什么数据,自己在 query 里写就行,不用等后端改接口。听起来很美好,但实际落地后,问题会逐渐暴露出来。

首先是学习成本。GraphQL 不是简单的 HTTP 请求,它有自己的 schema 定义、类型系统、query 语法、resolver 实现。前端要学会写 query 和 mutation,后端要学会设计 schema 和实现 resolver,测试同学要学会怎么构造 GraphQL 请求来测接口。对于一个小团队来说,这个成本不低。

其次是性能问题。GraphQL 的灵活性是把双刃剑。前端可以随意组合字段,但后端的 resolver 可能会执行大量的数据库查询或者 RPC 调用。如果前端写了一个嵌套很深的 query,比如"查询用户 → 查询用户的订单 → 查询订单的商品 → 查询商品的评价",后端可能会产生 N+1 查询问题。虽然可以用 DataLoader 优化,但这又增加了开发复杂度。

最关键的是协作模式的改变。GraphQL 的理想场景是前端完全自主,不依赖后端。但在实际业务中,前端真的能完全理解数据模型吗?我见过一个案例:前端同学在 query 里写了 `user { orders { items { product { category { parentCategory { ... } } } } }`,查询了5层嵌套关系,结果页面打开要等3秒,最后发现只是为了展示一个"商品类目"字段,完全可以在前端存一份类目映射表。

GraphQL 的本质是把 API 设计的复杂度从后端转移到了前端。如果团队没有足够的前端能力来驾驭这种灵活性,反而会增加协作成本。

我认为,GraphQL 更适合这些场景:
1. 数据模型复杂,查询场景多样:比如 GitHub、Shopify 这种平台,数据关系复杂,不同客户端的查询需求差异很大。
2. 团队规模大,前后端分工明确:有专门的后端团队负责 schema 设计和优化,前端团队有能力理解数据模型。
3. 对开发效率的要求高于性能:比如内部后台系统,查询量不大,但需求变化快,GraphQL 可以减少接口修改频率。

但对于大部分中小团队来说,RESTful + BFF 层可能是更合适的方案。

 

BFF 才是前后端协作的最优解

 

BFF(Backend for Frontend)这个概念不新,但很多团队没有真正用好。它的核心思想是:在前端和后端之间加一层中间层,专门为前端服务。

BFF 层的价值在于:
1. 解耦前后端:后端专注于业务逻辑和数据模型,前端专注于交互和展示,BFF 层负责数据的转换和聚合。
2. 提升开发效率:前端需要的数据结构,BFF 层可以直接提供,不用前端自己拼接多个接口。
3. 降低协作成本:前端和 BFF 层通常由同一个团队维护,沟通成本低,改起来快。

在金融业务中,BFF 层尤其有用。比如"持仓页"这个场景,前端需要展示用户的所有资产,包括定期理财、活期理财、基金、股票等。后端可能有多个服务,每个服务返回的数据结构不一样。如果让前端去调用多个接口再拼接数据,代码会非常复杂。这时候,BFF 层可以聚合这些数据,统一返回一个前端需要的结构。

BFF 层的另一个优势是可以用 Node.js 实现。对于有全栈能力的前端团队来说,用 Node.js 写 BFF 层几乎没有额外的学习成本,而且可以和前端共享代码(比如数据校验、类型定义)。我们团队的 BFF 层就是用 Node.js + TypeScript 实现的,前后端共享同一套类型定义,开发效率提升了不少。

当然,BFF 层也不是万能的。如果团队没有全栈能力,BFF 层可能会成为瓶颈。而且 BFF 层本质上是增加了一层服务,会带来额外的运维成本和性能损耗。但对于大部分业务来说,这个代价是值得的。

 

技术选型要从团队出发

 

回到最开始的问题:为什么我建议那个团队用 RESTful 而不是 GraphQL?

不是因为 GraphQL 不好,而是因为团队规模太小。3个后端、5个前端,大家都很忙,没有精力去学习和优化 GraphQL。而且业务场景相对简单,RESTful + BFF 层完全够用。如果强行上 GraphQL,可能会带来更多的问题。

技术选型的第一原则不是技术本身的先进性,而是团队的实际情况。如果团队有足够的能力和时间去驾驭一个新技术,那当然可以尝试。但如果团队已经很忙了,还要花大量时间学习新技术,那就得不偿失了。

我见过太多团队,盲目追求技术潮流,最后把自己搞得很痛苦。用 GraphQL 的团队,前端写了复杂的 query,后端发现性能问题又要优化;用微服务的团队,服务拆得太细,调试起来困难重重;用 Serverless 的团队,发现冷启动时间太长,用户体验很差。

技术选型不是选"最好的技术",而是选"最合适的技术"。RESTful 和 GraphQL 都有各自的适用场景,关键是要结合团队的实际情况,选择一个能解决问题、又不会带来太多额外成本的方案。

 

最后

 

这些年做全栈,最大的感受是:技术本身不是最难的,难的是理解业务、理解团队、做出合适的选择。

RESTful 和 GraphQL 都是好技术,但它们不是银弹。API 设计的核心不是遵守某个规范,而是让前后端协作更高效,让代码更容易维护,让业务价值更快落地。

如果你的团队正在纠结该用 RESTful 还是 GraphQL,我的建议是:先想清楚团队的能力和业务的需求,然后选择一个最简单、最直接的方案。别被技术的光环迷惑了眼睛。

技术是为了解决问题,不是为了炫技。

You voted 2. Total votes: 1

添加新评论