政策快报平台上线初期,接口设计采用的是RESTful风格。
一个资源对应一个接口------/api/policies获取政策列表,/api/policies/{id}获取政策详情,/api/users获取用户信息。简单直接,易于理解和维护。
但随着业务复杂度增加,RESTful开始暴露一些问题:
-
一个页面可能需要调用3-5个接口才能完成数据组装,前端代码越来越臃肿
-
不同页面需要的数据字段不同,但RESTful接口返回的字段是固定的,无法按需获取
-
移动端和PC端对数据的需求不同,但后端只能提供同样的数据结构
-
版本迭代时,修改一个接口可能影响多个前端页面
2025年初,我们开始将部分核心接口从RESTful迁移到GraphQL。本文复盘这个决策和迁移过程。
迁移的3个核心原因
原因一:减少前端请求数量
一个政策详情页,需要展示:
-
政策基本信息(标题、发文号、发布日期、截止日期、发文机关)
-
政策正文(带格式)
-
AI解读摘要
-
关联政策列表
-
用户行为状态(是否收藏、是否已读、是否分享过)
使用RESTful:需要调用5个接口,前端需要处理5次异步请求和5个加载状态,代码复杂度高,总加载时间也长。
使用GraphQL:1次请求,前端只需要处理1次请求和1个加载状态,代码简洁且响应时间更短。
原因二:按需获取字段
RESTful接口返回的是固定结构。移动端需要精简数据(只展示关键字段),PC端需要完整数据(展示所有字段),但接口是同一个。
使用GraphQL:前端可以精确指定需要的字段。移动端只请求"标题、摘要、日期"3个字段,PC端请求全部字段,一次请求满足两端需求,无需维护多个接口版本。
原因三:减少版本迭代成本
RESTful接口一旦上线,就很难删除字段(担心影响已有客户端)。于是接口中累积了大量"可能用到但实际没用"的字段,越来越臃肿。
使用GraphQL:新增字段不会影响已有查询,删除字段只影响使用了该字段的客户端,且前端可以立即感知并调整。版本迭代更灵活,不需要维护多个API版本。
RESTful vs GraphQL:对比数据
| 维度 | RESTful | GraphQL |
|---|---|---|
| 接口数量 | 3-5个/页面 | 1个/页面 |
| 字段冗余 | 高(固定返回全部字段) | 低(按需获取) |
| 前端代码复杂度 | 高(多接口协调) | 低(单接口查询) |
| 后端灵活性 | 低(修改影响所有客户端) | 高(按需返回) |
| 学习成本 | 低(标准HTTP) | 中(需学习GraphQL语法) |
| 缓存复杂度 | 低(URL级缓存) | 高(查询内容级缓存) |
迁移后的效果数据
-
政策详情页:接口调用从5次减少到1次
-
数据传输量:平均减少约40%(按需获取,不再传输冗余字段)
-
首屏加载时间:从1.8秒降至1.1秒(约39%的提升)
-
接口数量:从约120个RESTful接口精简到约30个GraphQL接口
遇到的主要问题
问题一:N+1查询问题
GraphQL的一个常见陷阱:嵌套查询时,如果后端没有做好数据加载优化,会导致数据库查询数量激增。
例如查询10条政策,每条政策需要查询对应的关联政策,可能导致1+10=11次数据库查询。
解决方案:使用DataLoader实现批量加载,将N次查询合并为1次批量查询。
问题二:缓存策略复杂化
RESTful接口可以通过URL做缓存,简单高效。
GraphQL查询内容不固定,无法按URL缓存,需要更复杂的缓存方案。
解决方案:使用Apollo Client的规范化缓存,按实体ID做缓存,而非按查询内容做缓存。
问题三:监控和日志需要升级
RESTful接口的监控可以通过URL聚合,简单直观。
GraphQL查询内容多样,需要按字段维度做监控。
解决方案:记录每个查询的字段结构,监控高频字段的响应时间和错误率。
从RESTful到GraphQL,不是"哪条路更先进"的问题,是"是否适合当前业务需求"的问题。
当接口数量膨胀、字段冗余严重、前端需要调用多个接口完成一个页面时,GraphQL是有效的解决方案。当业务简单、接口数量可控时,RESTful仍然足够。