REST vs. GraphQL:选择合适的 API 架构

发布: (2025年12月22日 GMT+8 03:27)
11 min read
原文: Dev.to

Source: Dev.to

TechBlogs

理解 REST:已确立的标准

REST(Representational State Transfer,表述性状态转移)是一种利用万维网原则的架构风格。它不是协议,而是一组约束,只要遵循这些约束,就能构建行为良好、可扩展且易于维护的分布式系统。REST 的核心思想是将每个资源(例如用户、产品、订单)视为可以通过唯一 URI(统一资源标识符)标识并使用标准 HTTP 方法进行操作的实体。

REST 的关键原则

  • 客户端‑服务器架构:
    客户端和服务器相互独立,只要它们之间的接口保持不变,就可以各自演进。

  • 无状态性:
    客户端对服务器的每个请求必须包含完成该请求所需的全部信息。服务器不应在请求之间存储任何客户端上下文。

  • 可缓存性:
    服务器的响应应指示其是否可被缓存。这使得客户端能够复用响应以处理后续请求,从而提升性能。

  • 分层系统:
    客户端通常无法判断它是直接连接到最终服务器,还是通过中间层进行通信。

  • 统一接口:最关键的约束

    • 资源标识: 在请求中使用 URI 标识资源。
    • 通过表述操作资源: 客户端接收资源的表述(如 JSON、XML),并可通过将这些表述发送回服务器来操作资源。
    • 自描述消息: 每条消息都包含足够的信息来描述如何处理它。
    • 超媒体作为应用状态的引擎(HATEOAS): 客户端应能够通过响应中提供的链接发现可用操作并在 API 中导航。虽然功能强大,但 HATEOAS 往往是 REST 实现中最少采用的部分。

REST 实践示例

假设我们正在构建一个电子商务应用。可能会有如下 RESTful 端点:

获取所有产品
GET /api/v1/products

[
  {
    "id": 1,
    "name": "Laptop",
    "price": 1200.00
  },
  {
    "id": 2,
    "name": "Keyboard",
    "price": 75.00
  }
]

获取特定产品
GET /api/v1/products/1

{
  "id": 1,
  "name": "Laptop",
  "price": 1200.00,
  "description": "Powerful and lightweight laptop."
}

创建新产品
POST /api/v1/products

{
  "name": "Mouse",
  "price": 25.00
}

更新产品
PUT /api/v1/products/2

{
  "price": 80.00
}

删除产品
DELETE /api/v1/products/2

REST 的优势

  • 简洁且易于理解: REST 被广泛认知和采用,开发者对 HTTP 方法和状态码通常很熟悉。
  • 可扩展性: 其无状态特性使系统具备高度可扩展性。
  • 可缓存性: 内置的 HTTP 缓存机制可以显著提升性能。
  • 面向资源: 资源与 URI 的清晰映射让 API 结构直观易懂。

REST 的劣势

  • 过度获取与不足获取: 客户端常会收到超出所需的数据(过度获取),或必须发起多次请求才能获取全部所需数据(不足获取)。
  • 端点激增: 随着应用规模扩大,端点数量可能变得难以管理。
  • 版本管理挑战: 管理 API 版本可能相当复杂。

介绍 GraphQL:用于 API 的查询语言

GraphQL 是一种用于 API 的查询语言,也是一个在已有数据上执行这些查询的运行时。由 Facebook 开发,它提供了比 REST 更高效、更强大且更灵活的替代方案。不同于 REST 由服务器定义 API 端点和返回的数据,GraphQL 允许客户端明确指定所需的数据。

GraphQL 的关键原则

  • 按需获取,恰好返回所需内容:
    客户端向服务器发送查询,指定所需的精确字段,避免了数据的过度获取。

  • 单一端点:
    通常,GraphQL API 只暴露一个端点(例如 /graphql),所有请求都发送到该端点。

  • 强类型模式(Schema):
    GraphQL API 通过模式(schema)定义,这是一份可查询数据的蓝图。模式描述了数据的类型、字段以及它们之间的关系。

  • 层级化数据获取:
    查询以层级结构组织,映射出请求数据的结构。

  • 变更(Mutations)和订阅(Subscriptions):
    变更允许客户端修改数据,订阅则实现实时更新。

GraphQL 实践:示例

使用我们的电子商务示例,GraphQL API 通常只有一个端点。客户端发送一个查询,明确指定所需的数据。

查询产品名称和价格

query {
  products {
    name
    price
  }
}

响应(JSON)

{
  "data": {
    "products": [
      {
        "name": "Laptop",
        "price": 1200.00
      },
      {
        "name": "Keyboard",
        "price": 75.00
      }
    ]
  }
}

注意我们只获取了 nameprice 字段,避免了过度获取。

查询特定产品的名称、描述以及其卖家的名称

假设 Product 类型上有一个 seller 字段。

query {
  product(id: "1") {
    name
    description
    seller {
      name
    }
  }
}

响应(JSON)

{
  "data": {
    "product": {
      "name": "Laptop",
      "description": "Powerful and lightweight laptop.",
      "seller": {
        "name": "Tech Gadgets Inc."
      }
    }
  }
}

此查询在一次往返中获取相关数据(卖家的名称),解决了 REST 的不足获取问题。

创建新产品的变更(Mutation)

mutation {
  createProduct(input: { name: "Mouse", price: 25.00 }) {
    id
    name
  }
}

响应(JSON)

{
  "data": {
    "createProduct": {
      "id": "3",
      "name": "Mouse"
    }
  }
}

GraphQL的优势

  • 高效的数据获取 – 通过让客户端精确请求所需数据,解决了获取过多或不足的问题。
  • 性能提升 – 更少的网络请求可以带来更快的用户体验,尤其在移动设备上。
  • 强类型模式 – 在客户端和服务器之间提供明确的契约,支持更好的工具、自动补全和验证。
  • 客户端灵活性 – 使前端开发者能够在不需要每次后端 API 更改的情况下演进数据需求。
  • 更易的 API 演进 – 可以向模式中添加新字段而不会破坏已有客户端。

GraphQL的弱点

  • 复杂性 – 与 REST 相比学习曲线更陡,尤其是对查询语言和模式定义新手而言。
  • 缓存 – 客户端缓存可能比 REST 的 HTTP 缓存更复杂;服务器端缓存也需要谨慎的策略。
  • 速率限制与安全 – 由于单一端点和灵活查询,实现细粒度的速率限制和安全措施更为棘手。
  • 工具成熟度 – 虽然发展迅速,但某些工具方面仍未达到成熟的 REST 生态系统的水平。

何时选择哪种方案

在 REST 与 GraphQL 之间的抉择取决于项目的具体需求、团队的专业技能以及预期的增长情况。

选择 REST 的情形

  • 您正在构建一个资源固定、数据需求可预期的简单 API。
  • 您的团队已经非常熟悉 REST 原则和相关工具。
  • 将现有的 HTTP 缓存机制作为重要优先级。
  • 您的应用规模为中小型,且对数据的过度获取或不足获取并不是主要问题。
  • 您需要与大量依赖 REST 约定的现有系统进行集成。

选择 GraphQL 的情形

  • 您的应用拥有复杂的数据需求以及资源之间的关联。
  • 您需要优化网络性能,尤其是针对移动客户端或数据需求多样的应用。
  • 您希望前端开发人员能够快速迭代 UI 与数据获取,而无需频繁依赖后端。
  • 您预期数据需求会频繁变化,或采用微服务架构,需要客户端从多个来源聚合数据。
  • 您重视强类型的 API 合约以及随之而来的工具链。

结论

REST 和 GraphQL 都是构建 API 的强大架构风格,各自拥有优势与不足。

  • REST 仍然是一个稳健、被广泛采用的标准——非常适合更简单的 API,并且能够充分利用 HTTP 的内置特性。
  • GraphQL 提供了一种现代、灵活且高效的方式——尤其适用于复杂的应用场景,在精确的数据获取和性能优化至关重要时表现出色。

通过了解它们的根本差异并结合项目的独特背景进行考量,你可以做出明智的选择,为你的 API 架构奠定成功基础,确保高效的数据交换并带来良好的开发者体验。

Back to Blog

相关文章

阅读更多 »