REST

核心思想:把一切看作资源,用 HTTP 方法表示操作。

  • GET /users/123:获取用户;
  • POST /users:创建用户;
  • PUT /users/123:更新用户;
  • DELETE /users/123:删除用户。

约束:无状态、统一接口、可缓存、分层系统。

优点:

  • 简单直观,学习成本低;
  • 可以利用 HTTP 的缓存机制(CDN、浏览器缓存);
  • 生态成熟,工具丰富;
  • 易于调试(用 curl 就能测试)。

常见问题:

一、过度获取(Over-fetching):客户端只需要用户名的列表,接口却返回了完整的用户对象。

二、获取不足(Under-fetching):要展示一个页面,需要调用多个接口(用户信息、订单列表、推荐商品……),产生"N+1 请求"问题。

三、版本管理:接口演进时,/v1、/v2 的版本管理可能变得繁琐。

GraphQL

由 Facebook 在 2015 年开源。

核心思想:客户端声明自己需要哪些数据,服务端按声明返回。

query {
  user(id: "123") {
    name
    orders(limit: 5) {
      id
      total
    }
  }
}

服务端只返回 name 和 orders 中指定的字段。

优点:

  • 按需获取:解决了过度获取问题;
  • 一次请求聚合多个资源:解决了获取不足问题;
  • 强类型 Schema:前后端有明确的契约,工具链(代码生成、自动补全、文档)支持好;
  • 前端可以自主调整所需数据,减少后端改接口的往返。

代价:

一、缓存更复杂。 所有请求都走 POST /graphql(同一个 URL + 不同的 body),HTTP 层的缓存机制难以直接使用。需要客户端侧的缓存方案(如 Apollo Client 的规范化缓存)。

二、查询复杂度不可控。 客户端可以构造极其复杂的嵌套查询,可能压垮服务端。

应对:查询深度限制、复杂度分析、分页限制、持久化查询(只允许预定义的查询)。

三、学习曲线。 需要理解 Schema、类型系统、解析器(Resolver)、DataLoader 等概念。

四、错误处理。 GraphQL 通常返回 200 状态码,错误信息在响应体的 errors 字段里——这与 HTTP 语义的集成需要额外设计。

怎么选

适合 REST:

  • 简单、稳定的资源型 API;
  • 需要充分利用 HTTP 缓存;
  • 团队对 REST 更熟悉;
  • 对外开放 API(客户端多样,REST 的通用性更好)。

适合 GraphQL:

  • 客户端需求多变(如多个前端平台,各自需要不同的数据形状);
  • 数据关系复杂,一个页面需要聚合多个来源;
  • 前端团队希望减少与后端的接口往返协调;
  • 有 BFF(Backend for Frontend)层的需求。

一个务实观察

GraphQL 并不是 REST 的"升级版",而是一种权衡不同的选择。

它把复杂度从"多次请求协调"转移到了"服务端查询优化和复杂度控制"。

很多团队在引入 GraphQL 后发现,真正的难点不在 API 层,而在数据聚合层的性能(如何高效地从多个数据源取数,避免 N+1 查询——这正是 DataLoader 要解决的问题)。

说明:本文为 API 设计的知识整理。