去年我参与了一个中型项目,团队决定用 GraphQL 替代 REST。 那时候我们觉得 GraphQL 特牛,前端想要啥就给啥,简直是 API 的终极形态。 后来发现事情没那么简单。 我们后端只有三个人,前端有五个人,GraphQL 给了前端无限自由,代价是后端每天收到一堆复杂查询。 有些查询嵌套了七八层,直接把我们 Postgres 数据库搞得满负载。 有一次一个列表页的 query 把数据库跑死了,因为某个 resolver 循环调了 N 次数据库。 我们查了半天,最后发现是典型的 N+1 查询,但 GraphQL 的 resolver 结构天生容易制造这种问题。
有人说 GraphQL 有 DataLoader 可以解决。 没错,我们后来也用了,但引入了更多的概念,缓存策略也变得异常复杂。 REST 时代我们可以用 HTTP 缓存,浏览器自带的,CDN 也能帮忙。 GraphQL 的端点固定是一个 POST,几乎没有缓存可以搞。 我印象特别深的是,有个用户首页需要多种数据,我们为了快,一次性拼一个大 query,结果服务端要聚合五六个服务的数据,响应时间从之前的 200ms 变成 1.2s。 前端倒是开心了,后端和运维苦不堪言。
后来我们痛定思痛,把 GraphQL 卸了,重新改回 REST。 但我们不是完全走老路,而是用了一种叫“按页面聚合 API”的方案,每个页面有一个专门的后端接口,后端自己组装数据。 前端拿到的还是一整个对象,但无需自己定义 query,性能和缓存都回来了,代码也简单多了。 我这个经历让我悟出一个道理:GraphQL 是一个很漂亮的工具,但它是给大公司那种复杂多客户端场景准备的。 像我们这种团队只有三个后端,根本没必要让每个前端随便查询。 技术选型不能光看酷不酷,要看自己的队伍和场景。
当然,我不否定 GraphQL。 在公共 API 提供给大量第三方开发者时,GraphQL 有它独特的价值,比如 GitHub、Shopify 那些。 但如果你是内部前后端,或者业务没那么复杂,REST 还是更实在。 GraphQL 让你觉得前端自主了,其实把问题转移了,后端从写接口变成了写 schema 和 resolver,还得操心性能。 这就像你雇了一个高级厨师,结果他每天都给你做一堆菜,你根本吃不完,还浪费食材。 说这么多,就是希望大家别被“革命性的 API”这种说法忽悠。 适合自己的才是真的好。