【译】关于GraphQL,你需要知道这些

作者:Weblab Technology | 译:kongfanjia

原文地址: https://medium.com/@weblab_tech/graphql-everything-you-need-to-know-58756ff253d8

【译者注:链接序号对应下面索引列表,另外可以点击阅读原文查看详细的链接文章】

在你已经构建并使用了 REST API 很长一段时间后,最近可能听说了一个 API 技术领域的的新星 —— GraphQL。有些人说它很好,但另一些人并不这么认为。现在,我相信你一定会好奇 GraphQL 到底是什么,它与传统方法有什么不同?

本文的主要目的是强调 GraphQL 的主要特性并讨论这一特定 API 规范的主要优点和缺点。

GraphQL 通常被描述为一种前端导向的 API 技术,因为它允许前端开发人员用比以前更简单的方式请求数据。Facebook 推出的这种查询语言的目的是以直观和可调的格式来制定客户端应用程序,来描绘其数据的先决条件及交互。最棒的一点是该语言不依赖于任何特定的数据库管理系统,并且被我们当前使用的数据格式和编码方式所支持。

传统 REST 的一个基本问题是客户端无法个性化请求数据集。除此之外,运行和控制多个接口是另一个难点,因为客户端总是需要从多个接口请求数据。

在搭建一个 GraphQL 服务器时,最重要的是用单一的 URL 入口来完成数据获取和更改。因此,用户可以通过传送一个说明所需内容的查询字符串来从服务器请求数据集。

在我们继续之前,在这里您可以找到我们的个人经验。

https://github.com/weblab-technology/graphql-example

GraphQL VS REST

REST 和 GraphQL 的相似之处是它们都用于构建 API 并且通过 HTTP 进行管理。

就差异而言,REST 主要是一个以网络为中心的软件的结构概念,没有规范,也不获取明确的工具集。它更专注于 API 的稳定耐用性而非最优的性能。

而 GraphQL 是一种设计用于通过 HTTP 在一个接口端点上工作的查询语言,从而提升性能和适配性。因此,我甚至会说,将查询语言和开发 Web 服务的架构风格进行比较可能看起来很奇怪。 其他一些显著差异包括:

数据获取

数据获取无疑是 GraphQL 最引入的最引人注目的优势之一。在一个用于产生或恢复数据的标准 REST API 中,我们可能需要向众多接口发出请求。相比之下,GraphQL 提供了单一接口入口,通过它我们可以访问服务器上可用的数据。

query {
books {
id
title
author
isbn
price
}
}

数据获取以外

由于 REST 规范中的每个接口都包含已确定的数据格式,因此相比 GraphQL, REST 会获取比你所需的要多的数据。同样的,REST 获取数据集相对简单,客户端可以提交额外的请求以获取相关数据。

对于 GraphQL 来说,情况就完全不同了。因为它是一种查询语言并支持声明式数据提取,所以用户可以只从服务器获得它们实际需要的数据。

只选择书名和价格:

query {
books {
title
price
}
}

错误管理

REST 规范中的错误管理非常简单。我们所需要做的就是检查 HTTP 协议头来查看响应的状态。根据状态代码,我们可以快速定位错误并获得解决该错误的合适方法。而在 GraphQL 中,我们总是会收到 200 OK 的状态码。

Request: query { books { error_field } }
Response:
Request Method:POST
Status Code: 200 OK
{“errors”:[{“message”:”Cannot query field \”error_field\” on type \”Book\”.”,”category”:”graphql”,”locations”:[{“line”:3,”column”:3}]}]}

缓存

由于 REST 采用的是支持缓存的 HTTP,因此可以使用它来避免重复获取资源。而 GraphQL 没有缓存系统,用户只能自己处理缓存的问题。

GraphQL 的优势

版本管理

当从 API EDGE 收回受限的数据控制时,任何改变都被视为重大变化,因此需要更新版本。这也许是大多数 API 选择版本管理的最大原因。如果在一个 API 中包含更新功能需要最新版本,则会在频繁发版与 API 解释和保留之间进行调整。

相比之下,GraphQL 只返回所需的数据,因此无需触发重大更改就可以通过最新的类型和字段来包含最近的功能。

弃用非常容易

在使用 GraphQL 时,你可以方便地弃用字段。GraphQL 用户必须在查询中说明他们需要的字段。

‘author_name’ => [
‘type’ => Type::string(),
‘deprecationReason’ => ‘Deprecated. Use author field’,
],

REST API 则以不同方式的工作。虽然基本路径可以在所有 REST API 中访问,但并非所有 REST API 都带有有稀有的属性。

相比之下,GraphQL 使得监控特定的字段使用情况变得非常容易。API 持有者可以知晓特定客户端弃用的字段。

性能优化

相比 REST 通常默认返回全部请求数据,GraphQL 通常是返回最少的所需要的请求数据。尽管事实上,如果 REST API 返回了基本部分的数据,使用 GraphQL 会默认传输更多的片段。

GraphQL的缺点

GraphQL 不容易缓存

REST 使用 HTTP 约定的存储方式,这使得当前的客户端和代理可以完美地工作来帮助服务器和客户端,而 GraphQL 则需要完全不同的方法。当然,当你必须重新排列数据集时,使用 REST 并非那么容易。你需要使用 Redis 集合并祈求你的客户端可以正常缓存。

正如官方文档 [1] 所说的那样,“在基于入口端点的 API 中,客户端可以使用 HTTP 缓存来确定两个资源是否相同,从而轻松避免重新获取资源。这些 API 中的 URL 是全局唯一标识符,客户端可以利用它来构建缓存。然而,在 GraphQL 中,没有类似 URL 的基元能够为给定对象提供全局唯一标识符。这里提供为 API 暴露这种标识符以供客户端使用的最佳实践。“

授权问题

授权问题也是我们在使用 GraphQL 时需要注意的一个重要问题。我们可以将 GraphQL 看作领域特定语言。 它仅仅是我们放在数据服务和客户端之间的中间层。授权完全是一个单独的层,语言本身不会帮助验证申请或使用。 但是,你可以使用 GraphQL 将客户端与预计的入口令牌关联起来。这与我们在 REST 中遵循的方法非常相似。

检测和解决 n + 1 问题

什么是 n + 1 问题?

n + 1 问题是后端实现 GraphQL 时可能面临的最明显的优化问题。

如果你没有优化你的 GraphQL 查询,你最终可能会在一次请求中进行多次查询。如果没有适当的缓存或批处理系统,每当确定一个字段时,普通的服务器都会向数据库发出新的请求。DataLoader 无疑是最好的解决方案,它可以极大地增强后端的性能,特别是在 GraphQL 服务器中。

用一个简单的例子来表示 n + 1 问题:

query {
users {
name
education {
degree
year
}
age
address {
country
city
street
}
}
}

使用 REST API 来评估、识别和解决 n + 1 问题相对容易。尽管这种情况与 GraphQL 有所不同。 幸运的是,Facebook 正在为这个问题开发一个可行的解决方案 —— DataLoader。

Dataloader 是什么?

DataLoader 主要是一个工具,用户可以使用它来读取数据并使其可以被 GraphQL 方法访问。我们可以使用此工具直接从记录中读取数据,而不是依赖 SQL 查询。

怎么运行的?

DataLoader 主要综合使用了批处理和缓存。它可以用于批量加载客户端查询的多个请求的回答。此外,它还会缓存回复并在连续查询相关类似资源时使用缓存。

GraphQL 中的 Queries、Mutations 和 Subscriptions

我们已经强调了一些有关 GraphQL 的重要内容。但是,为了开发一个功能齐全的应用程序,我们还需要了解一些可以用来提高我们工作的功能和性能的其他内容。

Queries

顾名思义,Queries 是客户端向服务器发出的数据请求。与 REST 采用的有明确的详细的格式的多个接口不同的是,GraphQL 仅有单一的入口接口,使客户端从预定义框架中确定实际需要的信息。

例如,

{
Users {
name
}
}

上文查询中的’Users’字段被称为根字段,而任何后面的数据被称为净载荷。

此查询将生成所有用户的名称列表。

{
“Users”: [
{“name”: “Damira”},
{“name”: “Michael”}
{“name”: “Salman”}
{“name”: “Sara”}
{“name”: “Maria”}
]
}

显而易见,这个查询返回了用户名(这是因为在我们的查询请求中,我们已经明确指出我们只需要名称列表)。 对于任何其他请求,我们需要为此添加具体的细节。

例如,假设我们希望从列表中访问最后3个用户的信息。 我们现在可以添加参数来实现这一点。

{
Users (last: 3) {
name
username
}}

所以,我们已经了解了如何使用’Queries’来从服务器获取数据。现在我们来看看在 GraphQL 中添加、忽略或更新数据的方式。

Mutations

Mutations 用于添加、更新或删除数据。该结构与查询几乎一致,除了你需要在开头添加“Mutations”这个词。 例如,

mutation {
createUser (name : “John”, username: ”jo123”){
name
username
}
}

Subscriptions

Subscriptions 可以用来设置和保留和服务器之间的实时连接。这使你可以获得有关相关事件的实时信息。大多数情况下,客户需要订阅特定的事件才能获取相应的数据。

请前往[官网文档](http://graphql.org/learn/queries/) 了解更多详情。

两全其美

尽管 GraphQL 解决了一些问题,但它仍然存在一些缺陷和不足,比如验证、策略和缓存等。 由于它本身是不确定的,它并没有指导用户如何应用。 除此之外,后端服务器与客户端之间存在一个非具体层可能会非常令人不安。

查看 Apollo Stack 提供的指南[2] 可以找出一些基本问题的答案。

如果你有一个正在运行的项目,那么你从原始的 RESTful API 迁移到到 GraphQL 将十分困难。 但好消息是,你可以同时使用这两种 API 技术来各取所需。

例如,你可以使用 GraphQL query 来开始重构前端获取数据的代码,然后开始整合 mutations。 它将允许你逐渐地减少控制器中的操作。

此外,还可以让这两种方法在你项目中的很长一段时期内同时工作。 例如,如果你想简化授权机制,你可以始终从 REST 框架获得帮助。

结论

回想起SOAP[3] 作为计算机网络中网络服务应用在交换结构化信息时采用的强大的协议规范,是 90 年代后期的热门并且得到了广泛的普及。然而,SOAP 相关的有效载荷明显较高,而且之前的应用程序碎片也会增加阻塞几率。

为了满足更实用和适应性更强地发布和利用网络服务,REST 作为一种新的方法出现了。这个概念非常简单直接,完全无状态,因此可以摒弃任何不相关的复杂因素。除此之外,这种方法还可以方便地与 JSON 和 XML 结合。但是,数据的一致性是最大的障碍。另外,关于如何管理版本的意见分歧也是一个问题。为了解决这些问题,Facebook 提出并为开发人员提供了一个两全其美的解决方案 – GraphQL。

GraphQL 并不是一个没有具体和实践基础说明的解决方案。 RESTful API 多年来在效率和性能方面都有很好的表现。GraphQL 弥补了 REST 的不足,而 REST 则填补了 GraphQL 中存在的空白。

值得注意的是,GraphQL 和 REST 的情况与关系型数据库和非关系型数据库的情况完全相同。

在使用 GraphQL 时,HTTP协议肯定是客户端与服务器通信协议的最佳选择,这主要是因为它的广泛性。 然而,当我们采用 HTTP 2 协议时,性能还是有问题的。

尽管 GraphQL 解决了现存的很多问题,但是选择任何一种 API 规范仍然很困难,因为你很可能在某个时候需要同时使用这两种规范。

从设计到应用的整体功能,选择 API 框架将对整个 API 过程产生影响。因此,这种选择必须是有远见的,而不是仅仅基于基本的信仰。

这篇文章完全是基于我对这两种方法的个人经验。我希望听到你们对 GraphQL 和 RESTful API 的意见或评论。 [欢迎关注“全栈探索”公众号,我们将定期推送全栈文章]

一些有用的刊物

https://github.com/weblab-technology/graphql-example

https://www.researchgate.net/publication/311989237ImplementingGraphQLasaQueryLanguageforDeductiveDatabasesinSWI-PrologUsingDCGsQuasiQuotationsand_Dicts

https://www.springer.com/gp

https://github.com/graphcool-examples/react-graphql

扩展阅读

[1] https://graphql.org/learn/caching/

[2] https://medium.com/apollo-stack/a-guide-to-authentication-in-graphql-e002a4039d1

[3] https://simple.wikipedia.org/wiki/SOAP_%28protocol%29

文章来源于 全栈探索 微信公众号,扫描下面二维码关注:

文章来源:

Author:甄玉磊
link:https://jdc.jd.com/archives/212690