当我们要创建数据驱动的 Web 或移动应用程序,需要开发后台 API,通过它可以从后端服务器来访问或操作数据。目前最流行的 API 架构是 REST,尽管 REST 广为人知并且通常易于使用,但它也有一些缺点,主要是包括冗余数据的过度获取、扩展效率低下。
GraphQL 是一种新型 API 架构,其设计比 REST 更灵活、更高效,具有声明式数据获取等功能。虽然 GraphQL 已经变得相当流行,但它并没有取代 REST,因为一些用户发现它更难使用,并认为它是一个过度设计的解决方案,特别是对于较小的应用程序来说。
在本文中,将深入探讨 REST 和 GraphQL 的优缺点,以便您可以决定哪种 API 架构最适合您的项目。
当前应用程序开发中 API 的主流架构是 REST,大多数后端框架将实现 REST。REST API 通常使用 HTTP 方法通过称为(例如GET /api/articles )的 URL 集合进行调用POST /api/articles。
Demo
以创建一个博客网站为例。在主页上,显示最新文章的摘要,包括标题、图像和简短说明。要为此提供数据,需要在后端服务器上设置一个 REST API,GET/api/articles它将以 JSON 数组的形式返回所需的数据,如下例所示:
// GET /articles
[
{
"id": 1,
"title": "REST is Awesome",
"image": "https://myrestblog.com/img/dsh9a89.png",
"description": "The benefits of REST"
},
{
"id": 2,
"title": "How REST Works",
"image": "https://myrestblog.com/img/33szad2.png",
"description": "Learn about REST"
}
]
REST 在很大程度上击败了 SOAP、WebService、XML 等较旧的 API 协议,并且尽管出现了 GraphQL 等较新的替代方案,但仍继续流行,其主要原因为:
易于实施
在 Web 服务器应用程序中设置 REST 很简单,尤其是当它使用 Java的 Springcloud或 Python 的 Requests 等 API 框架时。例如,使用 MongoDB 在 Express 应用程序中设置 REST 端点/articles就像调用数据库并将记录返回为 JSON 一样简单,如下所示:
app.get('/api/articles', async (req, res) => {
try {
const articles = await db.articles.find() res.json(articles)
} catch (err) {
res.status(500).send(err)
}
})
广泛理解和协同开发
无论 GraphQL 是否优于 REST,大多数开发人员都会同意,当您使用自己所知道的知识时,开发效率会更高。截至 2022 年,如果您有多个开发人员在开发您的应用程序,或者您有公共 API,则大多数消费者将熟悉 REST。
要理解为什么创建 GraphQL,我们需要首先看看 REST 的缺点
过度获取
回到博客的示例,假设创建了一个移动网站。与桌面版本一样,在主页上显示文章摘要。由于手机屏幕较小,这里的摘要只需要标题和图片,可以省略描述。不幸的是,由于GET /api/articles端点是固定的,移动版本description在调用 API 时仍然会收到该字段。这种低效率被称为“过度获取”,并且在发送大量数据时会成为挑战。
冗余数据效率低下
当对象包含表示相关实体的子对象时,该对象具有嵌套数据。例如,可能有一个带有嵌套评论对象的文章对象。由于实体在 REST 中被分配了自己唯一的URL,因此可能需要通过单独的 API 往返来填充嵌套数据。
例如,要获取一篇文章,我们首先使用端点GET /api/articles。要获取本文的评论,我们需要首先等待文章数据填充,以便我们知道在后续请求中需要获取哪些特定评论,如下面的代码示例所示。等待这些后续请求得到解决将增加用户在与页面交互之前必须等待的时间。
// GET /articles
[
{
"id": 1,
"title": "REST is Awesome",
"image": "https://myrestblog.com/img/dsh9a89.png",
"description": "An article about REST",
"comment_ids": [
10,
14,
22
]
},
{ ... }
]
REST 的低效率促使 Facebook 工程师在 2015 年创建了一种新的 API 设计,称为 GraphQL。GraphQL 迅速成为开发人员和公司的热门选择,推出了相关工具和服务的生态系统。与 REST 一样,GraphQL 不是一个特定的软件,而是 API 设计的规范。
为了了解 GraphQL 的优势,快速概述它的工作原理。与 REST 不同,GraphQL 需要一个架构来告诉客户端和服务器允许通过 API 执行哪些数据和操作。它们是使用 GraphQL 模式语言定义的——一种与语言无关的简单格式,具有强大的类型系统。
Demo
Article让我们回到具有和实体的博客网站的示例Comment。在我们的 GraphQL 模式中,我们定义Article具有必需的整数id字段和title、image、 和的可选字符串字段的类型description,如下所示:
type Article {
id: Integer!
title: String
image: String
description: String
}
除了基本标量类型之外,模式对象还可以相互引用。Article例如,我们可以在类型和类型之间创建一对多关系Comment,如下所示:
type Article {
id: Integer!
title: String
image: String
description: String
comments: [Comment]
}
type Comment {
content: String
article: Article
author: Author
}
模型定义
GraphQL 模式的另一个重要用途是定义操作,其中包括读取数据的查询和写入数据的突变。在这里,我们提供了 的查询Articles,其类型为文章数组:
type Article {
id: Integer!
title: String
image: String
description: String
comments: [Comment]
}
type Comment {
content: String
article: Article
author: Author
}
type Query {
articles: [Article]
}
通过对 GraphQL 的基本了解,我们现在可以了解它的主要优点。
声明式数据获取
GraphQL 的杀手级功能是声明式数据获取,客户端可以准确指定其需要的数据。这可以包括特定字段,甚至在嵌套对象内。我们之前看到,操作必须在模式上定义。不过,在这些操作中,我们可以指定希望查询返回哪些字段(最多达到架构的限制)。
例如,我们可以创建一个查询来Articles仅获取我们想要的字段,无论是否有嵌套Comments。请参阅下面的示例:
query {
articles {
id
title
image
description
comments {
content
}
}
}
这是将从该查询返回的数据结构。请注意,GraphQL 响应中收到的数据将与请求它的查询具有相同的形状。
{
"data": {
"articles": [
{
"id": 1,
"title": "REST is Awesome",
"image": "https://restblog.com/img/dsh9a8.png",
"description": "An article about REST",
"comments": [
{
"content": "GraphQL is better!"
},
{ ... }
]
}
],
...
}
}
通过这种方式,GraphQL 消除了过度获取和对嵌套数据的顺序调用的需要。
版本控制
每次应用程序发生变化时,API 也可能需要更改。例如,假设我们决定将实体description中的字段重命名Article为blurb. REST 通过提供多个版本来处理这个问题,例如/api/v1,api/v2这对于 API 开发人员和消费者来说都是很麻烦的。使用 GraphQL,可以从架构中删除已弃用的字段,而不会影响现有查询。这为应用程序提供了对新功能的持续访问,并鼓励更清洁、更易于维护的服务器代码。
虽然 GraphQL 为 REST 的缺点提供了一个优雅的解决方案,但请考虑一下 GraphQL 面临的一些批评。
取舍权衡困惑
一些开发人员认为 GraphQL 正在解决的问题常常被夸大了。例如,对于大多数小型应用程序来说,如果过度获取的几个字节的数据进入有效负载,这可能并不重要。
更难合作
另一个批评是 GraphQL 实现最终比 REST 更难编码,它还为新用户提供了更困难的学习曲线。
难以缓存
最后,GraphQL 经常因更难以缓存而受到批评,REST 客户端可以获得 HTTP 缓存的好处,因为所有端点都是 URL,而 GraphQL 客户端需要实现自己的自定义解决方案,如使用本地缓存,譬如redux-persit、localforage
虽然 REST 架构在过去十年中主导了 Web 开发,但它对设置端点的使用使其有些不灵活且低效。GraphQL 通过提供严格类型的模式语言来解决这些问题,消费者可以根据需要进行查询。