这个指南教你在不修改任何代码的情况下,完成从 REST 到 GraphQL 的迁移。这样,GraphQL 就能让你的 REST 真正休息一下了!

从 REST 到 GraphQL

GraphQL 的支持者在宣传推广 GraphQL 方面已经做得非常好了。出于对他们努力的尊重,我就不再深入介绍细节,只是稍微总结一下:

  1. GraphQL 允许我们在单个请求中获取多个资源;
  2. 通过精确描述所需数据,GraphQL 解决了 REST 过度抓取数据的问题;
  3. GraphQL 借助在一个请求中获取相关的数据,解决了前端 N 1 查询的问题。

本指南中,我会介绍大多数倡导 GraphQL 的人所忽略的一个点,就是“我们在 REST 上有了巨大投入”。这意味着:

虽然有许多文章帮我们从 REST 迁移到 GraphQL,但这些做法都迫使我们更改现有的代码库或在 REST 服务前面编写新的代码库。

但是,稍等一下……

如果它还能运行,就别去碰它。

这难道不是编程的第一规则吗?

迁移可能非常痛苦,尤其是面对巨大的代码库时,更会令人望而生畏。随时存在将已有功能破坏掉的可能性。

我们为什么不能继续保持 REST 呢?我们天性懒惰,都喜欢用简单的技巧和容易的解决方案。

如果有一种方式,让我们原样保持 REST 服务,且无需任何代码变更就能在其之上实现一个 GraphQL 层,那会怎样?听起来很神奇, Space Cloud 就能帮我们实现这一切

Space Cloud 是什么?

简而言之,Space Cloud 是一个开源的 Web 服务器,它能在数据库和微服务之上即时提供 GraphQL 和 REST API。

Space Cloud 最酷的一点在于,所有 API 都是实时的。我们可以选择订阅数据库的变更。在实现实时应用时,该功能非常便利。

本指南中,我们会用 Space Cloud 的remote service模块将 REST 服务迁移成 GraphQL。

架构

基于 REST 之上的 GraphQL 架构最终如下图所示:

大数据的表格的前端渲染性能(分分钟将REST转换为)(1)

我们的应用将会发起对 Space Cloud 的 GraphQL 查询,该请求又会访问服务器上的 REST 端点。在该场景中,Space Cloud 会作为 GraphQL 代理或 API 网关。

你可能注意到,Space Cloud 是一个单独的 GraphQL 层,位于 REST 服务之上。这种方式的优点在于REST 服务依然能够保持原样,已有的客户端可以直接使用它们。这样,从 REST 服务迁移至 GraphQL 不会破坏旧的客户端。

接下来,让我们开始。

我们将要构建什么?

本指南中,我们将会构建一个简单的算数服务,它包含如下端点:

求和计算端点将会返回两个数的和,这两个数是通过请求的body获取到的。翻倍计算端点将会对其接收到的值翻倍,初始值是通过 URL 路径参数获取到的。

现在,开始构建

第一步:编写服务

现在,我们开始编写 REST 服务。在这里,我们使用 NodeJS 和 express 来编写 REST 服务。

注意:你可以使用任意语言和框架来编写服务,只要它支持 HTTP 即可,因为这是 Space Cloud 用来与你的 REST 服务进行通信的协议。

首先,创建一个文件夹作为工作目录。

创建 NPM 项目

复制代码

npm init -y

安装 Express

复制代码

npm install --save express

编写 express 服务器

创建名为index.js的文件,并复制粘贴如下代码:

复制代码

var express = require("express");var app = express();app.use(express.json());app.post("/adder", function(req, res) { const num1 = req.body.num1; const num2 = req.body.num2; const response = { result: num1 num2 }; res.status(200).send(JSON.stringify(response));});app.get("/doubler/:num", function(req, res) { const num = req.params.num; const response = { result: num * 2 }; res.status(200).send(JSON.stringify(response));});var server = app.listen(5000, function () { console.log("app running on port:", server.address().port);});

可以看到,代码非常简单直接。我们只是使用 ExpressJS 创建了一个 HTTP 服务器并监听 5000 端口。

如前文所示,服务器包含两个端点:

  • 求和计算端点:我们预期从POST的 body 中接收到两个数字,即num1和num2,接下来所做的就是返回这两个数字的和。
  • 翻倍计算端点:我们将通过 URL 路径参数得到的数字乘以 2,然后返回。

对于服务来讲,我们做这些就足够了。

第二步:启动服务

要运行服务,我们只需执行如下命令即可:

复制代码

node index.js

我们让 REST 服务启动并运行了起来。接下来,启动 Space Cloud 并通过 GraphQL 来使用 REST 服务。

第三步:下载 Space Cloud

我们需要为自己的操作系统下载 Space Cloud 二进制文件,也可以通过其源码直接进行构建。如果从源码构建的话,需要 go 1.13.0 或更高版本。

可以通过以下链接下载对应操作系统的二进制文件:

  • Mac
  • Linux
  • Windows

下载后,我们解压压缩包。

对于 Linux/Mac:unzip space-cloud.zip && chmod x space-cloud

对于 Windows:右键点击压缩包并选择“解压到此处”。

为确保二进制文件的正确性,在二进制文件的解压目录下,运行如下命令:

对于 Linux/Mac:./space-cloud -v

对于 Windows:space-cloud.exe -v

它将会展现如下输出:

复制代码

space-cloud-ee version 0.13.0

第四步:下载 Space Cloud

要以dev模式启动 Space Cloud,可以复制粘贴如下命令并点击回车键:

对于 Linux/Mac:./space-cloud run --dev

对于 Windows:space-cloud.exe run --dev

在 Space Cloud 启动时,我们会看到如下所示的输出:

复制代码

Creating a new server with id auto-1T5fA9E1B2jeNUbV8R0fOPubRngStarting http server on port: 4122 Hosting mission control on http://localhost:4122/mission-control/ Space cloud is running on the specified ports :D

注意:--dev标记会告诉 Space Cloud 以 dev 模式运行(所以,admin UI 不会要求输入用户名和密码)。

第五步:配置 Space Cloud

我们注意到,Space Cloud 在工作目录生成一个config.yaml文件。

Space Cloud 需要该文件来完成它的功能。这个文件用来加载一些信息,包括要连接的 REST 服务器以及它们的端点。Space Cloud 有自己的 Mission Control(admin UI),借助它能够快速完成配置。

打开 Mission Control

导航至 http://localhost:4122/mission-control,可以打开 Mission Control。

注意:如果你不是在本地 Space Cloud 的话,那么需要将localhost替换为实际地址。

创建项目

点击Create a Project按钮,打开如下界面:

大数据的表格的前端渲染性能(分分钟将REST转换为)(2)

为你的项目设置一个name。

在这里选择什么数据库无关紧要,因为我们不会用到它。

点击Next创建项目。

第六步:添加远程服务到 Space Cloud 中

导航至 Mission Control 的Remote Services区域。

点击Add first remote service按钮来打开如下的表单:

大数据的表格的前端渲染性能(分分钟将REST转换为)(3)

将服务名设置为arithmetic,并将服务的 URL 设置为:

复制代码

http://localhost:5000

添加完远程服务之后,在远程服务的表格中,我们应该就能看到它:

大数据的表格的前端渲染性能(分分钟将REST转换为)(4)

点击 Actions 列中的Add按钮,将会打开服务页面。

点击Add first remote endpoint按钮,打开如下所示表单:

大数据的表格的前端渲染性能(分分钟将REST转换为)(5)

为求和计算端点添加如下内容:

  • Name:adder
  • Method:POST
  • Path:/adder

再次点击“Add”按钮并添加doubler端点:

  • Name:doubler
  • Method:GET
  • Path:/doubler/{args.num}

注意:现在不要担心{args.num}部分,只需要确保将 Method 设置为GET即可。

第七步:通过 GraphQL 来查询 REST 服务

现在,我们添加了 REST 和两个端点到 Space Cloud 中,接下来,我们该使用统一的 GraphQL API 对其进行查询。

跳转至Explorer区域:

大数据的表格的前端渲染性能(分分钟将REST转换为)(6)

尝试在 GraphiQL explorer 中运行如下的 GraphQL 查询:

复制代码

{ adder(num1: 10, num2: 20) @arithmetic { result }}

将会看到如下所示的响应:

复制代码

{ "adder": { "result": 30 }}

在得到上述 GraphQL 查询后,Space Cloud 会向 REST 服务发送如下的请求:

  • Method:POST
  • Path:/adder
  • Request Body:

复制代码

{ "num1": 10, "num2": 20}

这意味着我们传递给 GraphQL 查询的参数以 Request Body 的形式传递给了 REST 服务。

接下来,我们尝试使用如下的 GraphQL 查询来访问doubler端点:

复制代码

{ doubler(num: 50) @arithmetic { result }}

GraphQL 查询会被 Space Cloud 翻译成为对 REST 的调用,如下所示:

复制代码

GET /doubler/50

如果你还记得的话,我们添加到 Space Cloud 的 doubler 端点是这样的:

复制代码

/doubler/{args.num}

基于该端点,Space Cloud 能够知道它要从 GraphQL 中获取一个参数num,并使用它作为变量来形成路径/doubler/50。

成功调用后,我们会看到如下所示的响应:

复制代码

{ "doubler": { "result": 100 }}

额外奖励——服务链

如果成功遵循这个指南的话,我们会有一个奖励!这个 REST 到 GraphQL 的转换为我们解锁了一个超级强大的功能:服务链(Service Chaining)。

让我们来看一个场景:

  • 我们想要使用 the adder service 对两个数字求和;
  • 我们想把从 the adder service 得到的结果翻倍。

REST 方式

如果我们在客户端代码中使用 REST 的话,上述任务将会如下所示:

大数据的表格的前端渲染性能(分分钟将REST转换为)(7)

注意,我们从前端发出两个请求,就意味着往返时间会翻倍。它会导致较慢的响应时间和较差的用户体验。

GraphQL 方式

现在,如果我们将客户端从 REST 切换为使用 Space Cloud 的 GraphQL,那么我们的请求将会如下所示:

大数据的表格的前端渲染性能(分分钟将REST转换为)(8)

注意,在这里,我们只从前端发起了一次 GraphQL 查询到后端(Space Cloud)。而 Space Cloud 发起两次请求到 REST 服务器以满足该请求。但是,这些请求(从 Space Cloud 到我们的服务器)的往返时间是微不足道的,因为它们位于同一个网络中。

要完成上述任务,到 Space Cloud 的 GraphQL 查询如下所示:

复制代码

{ adder(num1: 10, num2: 20) @arithmetic { doubler(num: "adder.result") @arithmetic { result } }}

请注意,我们是如何在得到adder服务的响应后调用doubler服务的,而且我们将adder服务的result以参数形式传递给doubler服务。

查询结果将会如下所示:

复制代码

{ "adder": { "doubler": { "result": 60 } }}

可以猜到,我们得到的结果是 60,即 ((10 20) * 2)。

小提示:如果你想并行执行两个不相关 REST 服务的话,我们可以在一个请求中完成,如下所示:

复制代码

{ adder(num1: 10, num2: 20) @arithmetic { result } doubler(num: 50) @arithmetic { result }}

我把这个查询会得到什么响应作为作业留给读者。

结论

首先,鼓励一下自己,因为你完整地读完了该指南。

通过该指南,我们学到:

  • 从 REST 迁移到 GraphQL 不需要更改代码。
  • 我们不需要在 REST 和 GraphQL 之间进行非此即彼的选择。我们可以在同一个应用程序中同时支持 REST 和 GraphQL。
  • 借助 Space Cloud 来使用 GraphQL 会带来网络方面的收益,有助于减少往返时间。

除了从 REST 迁移到 GraphQL(如跨数据库连接)之外,我们还可以用 Space Cloud 做更多事情。

关注我并转发此篇文章,私信我“领取资料”,即可免费获得InfoQ价值4999元迷你书!

,