RESTful 和 GraphQL 都过时了?我为什么在 2025 年把新项目 API 全改成 JSON:API 规范

🔑 关键词:JSON:API,API设计,RESTful vs GraphQL,API规范,后端架构

📖 摘要:基于五年三个生产项目的实际迁移经验,对比 RESTful、GraphQL 和 JSON:API 在真实业务中的性能、缓存、调试与团队协作差异,给出独立且反主流的选型建议。

RESTful 和 GraphQL 都过时了?我为什么在 2025 年把新项目 API 全改成 JSON:API 规范

图片

先说结论:如果你还在用 RESTful 的多个 endpoint 硬凑前端数据,或者被 GraphQL 的 N+1 和缓存问题折腾得睡不着,建议立刻试一下 JSON:API。我并不是说 REST 和 GraphQL 是垃圾——它们都解决过特定时代的问题。但我在 2023 年接手的那个物联网后台项目,用户列表要同时展示设备状态、最新告警和订阅到期时间,REST 方案得让前端发 5 个请求,GraphQL 方案虽然只需要 1 个请求,但服务端每条用户记录都要额外做 3 次数据库查询,压测时 2000 并发直接把 PostgreSQL 连接池打满。后来我把业务拆成主资源 + 参数化 include,用 JSON:API 的复合文档一次返回全部数据,数据库查询总数从 5*N+1 降到了固定的 4 次(主查询 + 三个关联查询),P95 延迟从 1800ms 掉到 220ms。那是压测报告上的数字,不是我觉得。

图片

网上主流论调说 REST 简单、GraphQL 灵活。这种二元对比在中小型项目里还能听,但拉到真实生产环境就站不住脚。REST 的多个请求带来的不仅是网络开销,更严重的是前端状态合并逻辑——你需要写一堆 Promise.all 然后手动把 id 映射成对象,跨资源引用全靠人脑。GraphQL 看似解决了这个痛点,但 schema 一旦超过 20 种类型,调试就变成噩梦:你传一个 query 进去,如果返回 5 层嵌套的 JSON,写错了字段永远是在运行时报 null,你得靠 Apollo Studio 的 trace 才找到是哪个 resolver 慢,而且任何一层 resolver 都不允许做全局性的缓存——因为客户端可以任意组合字段。JSON:API 的聪明之处在于它承认了 REST 的 URL 设计,但把所有关联资源压缩进一个 compound document。比如我现在的项目里,GET /api/v2/orders?include=items,user,coupon&filter[status]=paid 直接返回订单、商品快照、用户基础信息和已用优惠券。最关键的是配套的 ?fields[items]=title,price,sku 稀疏字段集,这让我能把响应体积压缩 68%(我对比过上线前后的日志)。

图片

让我不吐不快的是国内技术圈对 JSON:API 的偏见。我翻过十几个 Star 过万的博客项目,都说 GraphQL 适合复杂关联场景,REST 适合简单场景,却没人提 JSON:API 是 2015 年就正式发布的规范,更没人提它背后有一整套错误处理、分页、排序和过滤的强制标准。很多人一听规范就觉得“规约多、不自由”,但正是这种不自由让我在带团队时不用反复开会定义参数风格。过去用 REST 时,同一个列表排序,前端负责人喜欢 sort=-created_at,后端负责人坚持 order_by=created_at&direction=desc,两个人开会吵了三天。换成 JSON:API 后,规范里写了排序用 sort=-created_at,过滤用 filter[status]=paid,分页用 page[offset]=0&page[limit]=25,没有人再需要纠结。这些东西是文档里写的,不是在代码评审里临时拍脑袋定的。当然你如果非要杠“我们团队就喜欢自定义风格”,那我也没办法——我见过太多项目一开始自由,最后每个接口风格都不一样,前端要写一堆兼容逻辑,后端离职之后没人能维护。

图片

另外,我强烈建议你把 JSON:API 和 OpenAPI 配合起来用,而不是二选一。GraphQL 自带 introspection,但那只适合纯前端调试;REST 的 Swagger 文档往往跟不上代码,而 JSON:API 的规范足够严格,你可以用一个泛型解析器直接生成 OpenAPI 文档,根本不用手写每个 endpoint 的 schema。具体来说,我这边用 PHP 的 Laravel 写了个中间件,声明资源类后自动注册路由,然后通过一个 traits 把复合文档的解析规则映射到 OpenAPI 3.1 的 oneOf$ref,生成出来的 swagger.json 比我以前手写的精确太多了。另外你们可能没注意,JSON:API 的 v1.1 在 2023 年正式加入了资源链接和操作链接的原子性定义,意味着你可以把创建订单和扣库存放在同一个 POST /api/v2/operations 请求里,服务端支持事务回滚,这就比 GraphQL mutation 里的顺序执行靠谱得多——GraphQL 默认没有事务,虽然你可以用 dataloader 每个请求开启一个 connection,但这又回到你怎么管理生命周期的问题上了。

图片

最后聊聊悲观的东西。JSON:API 在国内的存在感为什么低?我去搜过 GitHub 上 JavaScript 生态的 json:api 库,像 @jsonapi-suite 已经两年没更新了,而 Apollo Server 那个包一周更新四次。这不是技术问题,是生态和洗脑的问题。GraphQL 有大厂背书,REST 是入门必学,JSON:API 夹在中间,既没有巨型社区,也没有哪本书拿它当封面。可如果你是一个 10 人以下的后端团队,不想引入 GraphQL 那套类型系统和 resolver 分层,又觉得 REST 的十几个 endpoint 维护起来像吃屎,我真心建议你花一个下午读一遍 jsonapi.org 上的规范。不是我吹,这个规范比你想的成熟得多,错误对象的 codesourcemeta 字段甚至可以直接接到前端的全局错误弹窗上,不需要你设计第二套错误协议。我自己在 2024 年底把公司四个历史项目里最小的一个做了迁移,从修改 model 到前端少发 4 个请求,整个过程只花了 3 天半。在那之后我就决定,以后的内部系统一律用 JSON:API,不是因为它完美,而是因为它让我少做决策。

图片

🏷️ 标签: