REST vs. GraphQL:选择合适的 API 架构
Source: Dev.to
理解 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
}
]
}
}
注意我们只获取了 name 和 price 字段,避免了过度获取。
查询特定产品的名称、描述以及其卖家的名称
假设 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 架构奠定成功基础,确保高效的数据交换并带来良好的开发者体验。
