无头CMS:REST与JSON:API与GraphQL

逆流の鱼, 15 一月, 2021

Web曾经以服务器为中心,因为Web内容管理系统管理数据并将其转换为HTML响应。随着无头架构 的兴起,Web的一部分正变得以服务器为中心,以数据为中心,而以客户端为中心,使其呈现。越来越多的数据在浏览器中呈现为HTML。

责任的转移产生了JavaScript框架,而在服务器端,它导致了JSON:API和GraphQL的发展,以更好地为这些JavaScript应用程序提供内容和数据。

在此博客文章中,我们将比较REST,JSON:API和GraphQL。首先,我们将研究与CMS无关的体系结构比较,然后评估一些Drupal特定的实现细节。

值得注意的是,在比较这三种方法时,当然会有很多复杂性,并且“取决于”。当我们讨论REST时,我们指的是“典型的REST API”,而不是经过精心设计或遵循某种规范(不是REST的概念)。当我们讨论JSON:API时,我们指的是JSON:API规范的实现。最后,当我们讨论GraphQL时,我们指的是实际使用的GraphQL。形式上,它只是一种查询语言,不是构建API的标准。

架构比较对于任何构建解耦应用程序的人都应该是有用的,无论它们使用什么基础,因为我们将评估的质量适用于大多数Web项目。

为了进行比较,让我们确定大多数使用Web服务的开发人员都关心以下素质:

  1. 请求效率:在一次网络往返中检索所有必要的数据对于性能至关重要。请求和响应的大小均应有效利用网络。
  2. API探索和架构文档: API应该易于理解并且易于发现。
  3. 操作简便:该方法应易于安装,配置,运行,扩展和安全。
  4. 编写数据:并非每个应用程序都需要在内容存储库中存储数据,但是在存储数据时,它不应比读取复杂得多。

我们在下表中总结了我们的结论,但在下面更深入地讨论了这四个类别(或表中的行)。如果汇总表中的颜色,则会看到我们将JSON:API排在GraphQL之上,将GraphQL排在REST之上

休息JSON:APIGraphQL

要求效率较差的; 需要多个请求才能满足共同的需求。回应are肿。优秀的; 通常,单个请求就可以满足大多数需求。可以定制响应以仅返回所需的内容。优秀的; 通常,单个请求就可以满足大多数需求。响应仅包含所要求的内容。

文档,API探索性和架构较差的; 没有模式,无法探索。可以接受;仅通用模式;链接和错误消息是自记录的。优秀的; 精确的模式;探索和记录的出色工具。

操作简便可以接受;开箱即用的CDN和反向代理;几乎不需要客户端库。优秀的; 可以与CDN和反向代理一起使用,无需客户端库,但许多库都可用且有用。较差的; 通常需要额外的基础结构客户端库是实际必需的,要从CDN和浏览器缓存中受益,需要特定的模式。

写数据可以接受;HTTP语义给出了一些指导,但是具体细节如何留给每个实现,每个请求写一次。优秀的; 规范清楚地定义了如何处理写操作,每个请求一次写操作,但是规范中增加了多次写操作。较差的; 写入的处理方式留给每个实现,并且有相互竞争的最佳实践,有可能在单个请求中执行多次写入。

如果您不熟悉JSON:API或GraphQL,建议您观看以下两个简短视频。它们将为本博文的其余部分提供有价值的背景信息:

要求效率

大多数REST API都倾向于最简单的实现:只能从一个URI检索资源。如果要检索第42条,则必须从中检索https://example.com/article/42。如果要检索第42条和第72条,则必须执行两次请求;一个https://example.com/article/42和一个https://example.com/article/72。如果文章的作者信息存储在其他内容类型中,则您必须执行两个附加请求,例如https://example.com/author/3https://example.com/author/7。此外,在您请求,检索和解析文章请求之前,您无法发送这些请求(否则您将不知道作者ID)。

因此,建立在基本REST API之上的客户端应用程序往往需要许多连续的请求来获取其数据。通常,只有在较早的请求得到满足之前,才可以发送这些请求,从而给网站访问者带来缓慢的体验。

开发GraphQL和JSON:API是为了解决REST API的典型低效率问题。使用JSON:API或GraphQL,您可以使用单个请求来检索第42条和第72条,以及每条的作者信息。它简化了开发人员的体验,但更重要的是,它加快了应用程序的速度。

最后,JSON:API和GraphQL都有限制响应大小的解决方案。对典型REST API的普遍抱怨是,它们的响应可能非常冗长。他们经常以远远超出客户需求的数据来响应。这既烦人又效率低下。

GraphQL通过要求开发人员向每个查询显式添加每个所需的资源字段来消除此问题。这使得难以过度获取数据,但很容易导致很大的GraphQL查询,从而使(可缓存的)GET请求变得不可能。

JSON:API通过稀疏字段集或所需资源字段列表的概念解决了这一问题。它们的行为与GraphQL几乎相同,但是,当省略它们时,JSON:API通常将返回所有字段。但是,优点是,当JSON:API查询太大时,可以忽略稀疏字段集,以便请求保持可缓存状态。

休息JSON:APIGraphQL

单个响应中包含多个数据对象通常;但每个实现都是不同的(对于Drupal:需要自定义“ REST导出”视图或需要自定义REST插件)。是是

嵌入相关数据(例如每篇文章的作者)没有是是

数据对象仅需要的字段没有是; 服务器可能会选择合理的默认值,因此开发人员必须努力防止过度获取。是; 严格,但消除了过度获取,极端情况下,它可能导致不良的可缓存性。

文档,API探索性和架构

作为使用Web服务的开发人员,您希望能够快速,轻松地发现和理解API:哪些资源可用,每个资源都有哪些字段,它们之间的关系等等。但是,如果这字段是日期或时间,指定的日期或时间是哪种机器可读格式?良好的文档资料和API探索可能会带来不同。

休息JSON:APIGraphQL

自动生成的文档依靠; 如果使用OpenAPI标准。依靠; 如果使用OpenAPI标准。是; 提供各种工具。

互动性较差的; 导航链接很少可用。可以接受;观察响应中的可用字段和链接可以探索API。优秀的; 自动完成功能,即时结果或编译错误,完整的上下文文档。

可验证的可编程模式。依靠; 如果使用OpenAPI标准。依靠; JSON:API规范定义了通用模式,但是尚无可靠的字段级模式。是; 提供了一个完整而可靠的模式(很少有例外)。

借助GraphiQL(在上面的视频中演示),GraphQL具有出色的API开发能力,GraphiQL是一种浏览器内置的IDE,可让开发人员迭代地构造查询。当开发人员输入查询内容时,可能会提供建议并可以自动完成。任何时候都可以运行查询,并且GraphiQL将在查询旁边显示实际结果。这为查询生成器提供了即时的,可操作的反馈。他们打错字了吗?响应看起来像所期望的吗?此外,需要其他上下文时,可以将文档召集为弹出窗口。

另一方面,JSON:API更不言自明:仅使用Web浏览器就可以探索API。在浏览器中,您可以从一种资源浏览到另一种资源,发现其字段等等。因此,如果您只想调试或尝试某些操作,则仅使用cURL或浏览器即可使用JSON:API 。或者,您可以使用Postman(如上面的视频所示)—一种独立的环境,可以在任何基于HTTP的API之上进行开发。但是,构造复杂的查询需要一些知识,而这就是GraphQL的GraphiQL与JSON:API相比所具有的优势。

操作简便

我们使用术语“操作简便性”来涵盖安装,配置,运行,扩展和保护每个解决方案的简便程度。

该表应该是不言自明的,但是我们想提供有关“可伸缩性”行的更多详细信息。为了扩展基于REST或基于JSON:API的Web服务以使其能够处理大量流量,您可以使用网站(和Drupal)已经使用的相同方法,包括反向代理(如Varnish或CDN)。要扩展GraphQL,如果没有持久查询,就不能像REST或JSON:API那样依赖HTTP缓存。持久查询不是官方GraphQL规范的一部分,但它们是GraphQL用户之间广泛采用的约定。他们实质上将查询存储在服务器上,为其分配ID,并允许客户端使用来获取查询结果。GET仅带有ID的请求。持久查询增加了操作的复杂性,这也意味着体系结构不再完全脱钩-如果客户端要检索不同的数据,则需要在服务器端进行更改。

休息JSON:APIGraphQL

可扩展性:其他基础架构要求优秀的; 与常规网站相同(Varnish,CDN等)。优秀的; 与常规网站相同(Varnish,CDN等)。通常较差;只有最简单的查询才能使用GET请求;为了获得GraphQL的全部好处,服务器需要自己的工具。

工具生态系统可以接受;提供了许多开发人员工具,但是为了获得最佳体验,需要针对实现对其进行自定义。优秀的; 许多可用的开发人员工具;工具不需要特定于实现。优秀的; 许多可用的开发人员工具;工具不需要特定于实现。

典型故障点更少; 服务器,客户端。更少; 服务器,客户端。许多; 服务器,客户端,客户端缓存,客户端和构建工具。

写数据

对于大多数REST API和JSON:API,编写数据就像获取数据一样容易:如果您可以读取信息,那么您也知道如何编写数据。GET您可以使用POSTPATCH请求,而不使用HTTP请求类型。JSON:API通过消除实现之间的差异对典型的REST API进行了改进。只有一种方法可以实现更好的通用工具,并减少花费在服务器端细节上的时间。

GraphQL的写操作(称为变种)的性质意味着您必须为每个写操作编写自定义代码。与JSON:API规范不同,GraphQL并未规定处理资源写操作的单一方法,因此存在许多相互竞争的最佳实践。本质上,GraphQL规范针对读取而非写入进行了优化。

另一方面,GraphQL规范针对已实现的突变自动支持批量/批量操作,而JSON:API规范则不支持。执行批写操作的能力可能很重要。例如,在我们的运行示例中,向文章添加新标签将需要两个请求。一种创建标签,另一种更新文章。也就是说,规范的路线图上支持JSON:API中的批量/批量写入

休息JSON:APIGraphQL

写数据可以接受;每个实现都是不同的。没有批量支持。优秀的; JSON:API规定了用于处理写入的完整解决方案。批量操作即将推出。较差的; GraphQL支持批量/批处理操作,但设计和实现写操作可能会比较棘手。有相互竞争的约定。

Drupal特定的注意事项

到目前为止,我们已经提供了架构和CMS无关的比较;现在,我们还想强调一些Drupal特定的实现细节。为此,我们可以查看安装的简易性,自动生成的文档,与Drupal实体和现场级访问控制系统的集成以及解耦过滤。

如果没有贡献的REST UI模块,Drupal 8的REST模块实际上是不可能建立的,其配置可能令人望而却步。在这一点上,Drupal的JSON:API模块远远优于Drupal的REST模块。设置很简单:安装完毕,就可以完成;没有什么可配置的。GraphQL模块也易于安装,但需要进行一些配置。

客户端生成的集合查询使使用者可以按照自己的兴趣过滤应用程序的数据。这类似于Drupal View,不同之处在于使用者可以添加,删除和控制所有过滤器。这几乎始终是公共Web服务的要求,但由于创建或更改列表不需要服务器端配置更改,因此它也可以使开发更高效。

Drupal的REST模块不支持客户端生成的集合查询。它需要由站点管理员设置“ REST视图显示”,并且由于这些需要在Drupal中手动配置;这意味着客户无法使用其所需的过滤器来编写自己的查询。

JSON:API和GraphQL,客户端无需服务器端配置即可执行自己的内容查询。这意味着它们可以真正分离:对前端的更改并不一定总是需要对后端配置进行更改。

这些客户端生成的查询与JSON:API模块一起使用比与GraphQL模块一起使用要简单一些,因为每个模块如何处理Drupal广泛的访问控制机制。默认情况下,JSON:API通过更改传入的查询来确保遵守这些要求。相反,GraphQL要求使用者具有简单绕过访问限制的权限。

大多数使用GraphQL不能授予此权限的项目都使用持久查询而不是客户端生成的查询。这意味着要返回到更传统的类似于Views的模式,因为使用者不再完全控制查询的过滤器。为了重新获得客户端生成的查询的某些效率,可以使用前端构建工具来自动创建这些持久查询。

休息JSON:APIGraphQL

易于安装和配置较差的; 需要贡献的模块REST UI,通过更改配置轻松破坏客户端。优秀的; 零配置!较差的; 使用起来较为复杂,可能需要其他权限,配置或自定义代码。

自动生成的文档可以接受;需要贡献模块OpenAPI。可以接受;需要贡献模块OpenAPI。优秀的; 包括GraphQL Voyager。

安全性:内容级访问控制(实体和现场访问)优秀的; 尊重内容级别的访问控制。优秀的; 即使在查询中,也要尊重内容级别的访问控制。可以接受;一些用例需要消费者具有绕过所有实体和/或字段访问的权限。

解耦过滤(客户端无需服务器端干预即可进行查询)没有是依靠; 仅在某些设置中以及其他工具/基础架构。

这对Drupal的路线图意味着什么?

Drupal成长为一个传统的Web内容管理系统,但此后就发展为API第一世界,行业分析师对此表示赞赏

作为Drupal的项目负责人,一段时间以来,我一直在谈论为JSON:API和GraphQL添加现成的支持。其实,我一直 看好  GraphQL自2015年我的乐观是正当的; 在整个Web开发行业中,GraphQL的兴趣正在飞速增长。

基于此分析,出于Drupal核心的需求,我们将JSON:API置于GraphQL之上,并将GraphQL置于REST之上。因此,我想更改对Drupal 8内核的建议。我相信不要将JSON:API和GraphQL都添加到Drupal 8内核中,我相信应该只添加JSON:API。就是说,Drupal的GraphQL实现非常棒,特别是当您具有开发人员能力来为项目构建定制的API时。

在评估REST,JSON:API和GraphQL模块的四种品质上,JSON:API的表现优于同期的产品。它基于Web标准的方法,开箱即用的读写能力,安全模型和易于操作的特性使其成为Drupal内核的最佳选择。此外,在JSON:API表现不佳的地方,我相信我们有真正的机会为规范做贡献。实际上,此博客文章的JSON:API模块维护者之一和合著者Gabe SulliceAcquia)最近亲自成为了JSON:API规范编辑器。

这个决定并不意味着您不能或不应该将GraphQL与Drupal一起使用。虽然我相信JSON:API涵盖了大多数用例,但在一些有效的用例中GraphQL非常适合。我很高兴Drupal拥有如此活跃的贡献模块生态系统,为Drupal的用户提供了很多选择。

我很高兴看到JSON:API规范及其Drupal的实现在未来数月和数年中的应用。下一步,我们正在准备将JSON:API添加到Drupal 8.7中。

特别感谢Wim LeersAcquia)和Gabe SulliceAcquia)共同撰写了此博客文章,并感谢Preston SoAcquia)和Alex BronsteinAcquia)在撰写过程中的反馈。

— Dries Buytaert

评论