GraphQL 简介

GraphQL 是从远程服务器查询数据的强大工具,也是我构建 API 的首选方式。对一些人来说,学习它可能有一定难度,因为教程通常使用 Apollo 或 Relay 等工具进行编写。

这些工具很不错,但通常更适用于复杂项目。在某些情况下,最好选择更轻量级的方法,并且不要通过添加额外的库增加包大小。

在这种情况下,你可以直接使用浏览器中提供的工具,在本快速教程中,我们将使用在你的浏览器中通常可用的 fetch

让我们首先简单地回顾一下 fetch 是什么以及它如何通常与 REST API 一起使用,在这之后我们就可以开始执行简单的 GraphQL 查询了。

图片

使用 Fetch 进行 GET 请求

Fetch 是用于发送网络请求的现代替代品,取代了较旧的 XMLHttpRequest 工具。它解决了从服务器获取数据时出现的一些问题,例如 Promise 链式处理。

虽然我们不会在本文详细讨论较旧的 XMLHttpRequest,但重要的是因历史原因你需要知道 fetch 在较旧的浏览器中不受支持。

关于 fetch 在浏览器之外的使用,在 Node.js 17 中你可以作为实验性功能直接使用它,在较早版本中,你可以安装比如 node-fetch 库。

以下是一个用于获取数据简单请求示例:

<section><span><span></span><span></span><span></span></span><span> </span></section><pre data-title="true"><code data-line="42"><span><span>const</span> url <span>=</span> <span>'<a target="_blank" rel="noopener noreferrer" href="https://query1.finance.yahoo.com/v8/finance/chart/BTC-USD">https://query1.finance.yahoo.com/v8/finance/chart/BTC-USD</a>'</span><br></span><span><br></span><span><span>const</span> options <span>=</span> <span>{</span><br></span><span>  <span>method</span><span>:</span> <span>'GET'</span><span>,</span><br></span><span><span>}</span><br></span><span><br></span><span><span>fetch</span><span>(</span>url<span>,</span> options<span>)</span><br></span><span>  <span>.</span><span>then</span><span>(</span><span>(</span><span>response</span><span>)</span> <span>=&gt;</span> <span>{</span><br></span><span>    <span>return</span> response<span>.</span><span>json</span><span>(</span><span>)</span><br></span><span>  <span>}</span><span>)</span><br></span><span>  <span>.</span><span>then</span><span>(</span><span>(</span><span>data</span><span>)</span> <span>=&gt;</span> <span>{</span><br></span><span>    <span>const</span> res <span>=</span> data<span>.</span><span>chart</span><span>.</span><span>result</span><br></span><span>    <span>console</span><span>.</span><span>info</span><span>(</span>res<span>)</span><br></span><span>    <span>return</span> res<br></span><span>  <span>}</span><span>)</span><br></span><span>  <span>.</span><span>catch</span><span>(</span><span>(</span><span>err</span><span>)</span> <span>=&gt;</span> <span>{</span><br></span><span>    <span>console</span><span>.</span><span>log</span><span>(</span><span>'err'</span><span>,</span> err<span>)</span><br></span><span>  <span>}</span><span>)</span><br></span></code></pre>

我们可以看到在 fetch 函数中传入了两个参数,即 URLoptions 参数。

options 用于附加配置,比如请求的方法、头部信息、跨源资源共享(CORS)配置以及 POST 请求时的主体内容。

随后的 .then() 调用允许我们链式处理异步 promise,这意味着你首先需要等待来自 API 的结果。如果成功,我们将获得响应,并使用 .json() 方法进行转换。

然后再次等待转换结果,在这里最终可以将数据记录到控制台上。

<section><span><span></span><span></span><span></span></span><span> </span></section><pre data-title="true"><code data-line="69"><span><span>{</span><br></span><span>  <span>"data"</span><span>:</span> <span>{</span><br></span><span>    <span>"allFilms"</span><span>:</span> <span>{</span><br></span><span>      <span>"films"</span><span>:</span> <span>[</span><br></span><span>        <span>{</span><br></span><span>          <span>"title"</span><span>:</span> <span>"A New Hope"</span><span>,</span><br></span><span>          <span>"releaseDate"</span><span>:</span> <span>"1977-05-25"</span><br></span><span>        <span>}</span><span>,</span><br></span><span>        <span>{</span><br></span><span>          <span>"title"</span><span>:</span> <span>"The Empire Strikes Back"</span><span>,</span><br></span><span>          <span>"releaseDate"</span><span>:</span> <span>"1980-05-17"</span><br></span><span>        <span>}</span><br></span><span>      <span>]</span><br></span><span>    <span>}</span><br></span><span>  <span>}</span><br></span><span><span>}</span><br></span></code></pre>

你会注意到 .catch() 方法尚未被触发。如果一切正常运行,只有成功的回调函数会被执行;但是,如果我们在请求过程中遇到错误,则会触发错误回调。

使用 Fetch 进行 GraphQL 查询

在先前的示例中,我们使用了雅虎金融的公共 REST API 来执行 GET 请求以检索数据。在第二个示例中,我们需要 Star Wars API 的 GraphQL 接口。

GraphQL 提供了所谓的模式内省,它允许我们轻松地记录可以从服务器检索到什么数据,你可以在文档链接中看到。

为了执行 GraphQL 查询,我们需要使用 POST 方法,设置内容为 application/json,并且将字符串化的 GraphQL 文档发送至 JSON 主体。

附加到请求的 GraphQL 文档将如下所示:

<section><span><span></span><span></span><span></span></span><span> </span></section><pre data-title="true"><code data-line="92"><span><span>query</span> <span>(</span><span><span>$first</span><span>:</span> <span>Int</span></span><span>)</span> <span>{</span><br></span><span>  <span>allFilms</span><span>(</span><span><span>first</span><span>:</span> $first</span><span>)</span> <span>{</span><br></span><span>   films <span>{</span><br></span><span>    title<br></span><span>    releaseDate<br></span><span>   <span>}</span><br></span><span>  <span>}</span><br></span><span><span>}</span><br></span></code></pre>

查询类似于 REST API 中的 GET 请求,只检索数据。使用 GraphQL,我们需要准确描述要检索的数据。你可以看到我们已经指定了要检索具有标题和发布日期的电影。

$first 是所谓的变量,这是必要的以将动态数据传递给查询,并允许我们从查询中获取前 n 个电影。现在让我们转换成 JavaScript 代码:

<section><span><span></span><span></span><span></span></span><span> </span></section><pre data-title="true"><code data-line="136"><span><span>const</span> url <span>=</span> <span>'<a target="_blank" rel="noopener noreferrer" href="https://swapi-graphql.netlify.app/.netlify/functions/index">https://swapi-graphql.netlify.app/.netlify/functions/index</a>'</span><span>;</span><br></span><span><br></span><span><span>const</span> <span>GET_FILMS</span> <span>=</span> <span><span>`</span><span>query ($first: Int) {<br></span></span></span><span><span><span>  allFilms(first: $first) {<br></span></span></span><span><span><span>   films {<br></span></span></span><span><span><span>    title<br></span></span></span><span><span><span>    releaseDate<br></span></span></span><span><span><span>   }<br></span></span></span><span><span><span>  }<br></span></span></span><span><span><span>}</span><span>`</span></span><span>;</span><br></span><span><br></span><span><span>const</span> options <span>=</span> <span>{</span><br></span><span>  <span>method</span><span>:</span> <span>'POST'</span><span>,</span><br></span><span>  <span>headers</span><span>:</span> <span>{</span><br></span><span>    <span>'Content-Type'</span><span>:</span> <span>'application/json'</span><span>,</span><br></span><span>  <span>}</span><span>,</span><br></span><span>  <span>body</span><span>:</span> <span>JSON</span><span>.</span><span>stringify</span><span>(</span><span>{</span><br></span><span>    <span>query</span><span>:</span> <span>GET_FILMS</span><span>,</span><br></span><span>    <span>variables</span><span>:</span> <span>{</span><br></span><span>      <span>first</span><span>:</span> <span>2</span><br></span><span>    <span>}</span><br></span><span>  <span>}</span><span>)</span><br></span><span><span>}</span><span>;</span><br></span><span><br></span><span><span>const</span> <span>fetchAPI</span> <span>=</span> <span>async</span> <span>(</span><span>)</span> <span>=&gt;</span> <span>{</span><br></span><span>  <span>try</span> <span>{</span><br></span><span>    <span>const</span> result <span>=</span> <span>await</span> <span>fetch</span><span>(</span><br></span><span>      url<span>,</span><br></span><span>      options<br></span><span>    <span>)</span><span>;</span><br></span><span>    <span>const</span> data <span>=</span> <span>await</span> result<span>.</span><span>json</span><span>(</span><span>)</span><span>;</span><br></span><span>    <span>console</span><span>.</span><span>info</span><span>(</span>data<span>)</span><span>;</span><br></span><span>  <span>}</span> <span>catch</span> <span>(</span>err<span>)</span> <span>{</span><br></span><span>    <span>console</span><span>.</span><span>info</span><span>(</span>err<span>)</span><br></span><span>  <span>}</span><br></span><span><span>}</span><br></span><span><span>await</span> <span>fetchAPI</span><span>(</span><span>)</span><span>;</span><br></span></code></pre>

我们已经为 GraphQL API 和我们的 GraphQL 文档定义了 URL。在这种情况下,我们需要将选项指定为第二个参数。

如上所述,选项方法需要设置为 POST,并且内容应该设置为 application/jsonbody 应该是有两个键的字符串化 JSON:

  • query:我们将传递 GraphQL 文档

  • variables:这些变量应该与服务器上文件和模式中的变量定义匹配

你还可以注意到,在第一个使用 GET 请求的示例中, 我们使用了 .thenable() Promise 链接方式,但在此处我们已经使用了 async await

现在,当我们执行结果时,我们会得到以下结果:

<section><span><span></span><span></span><span></span></span><span> </span></section><pre data-title="true"><code data-line="167"><span><span>{</span><br></span><span>  <span>"data"</span><span>:</span> <span>{</span><br></span><span>    <span>"allFilms"</span><span>:</span> <span>{</span><br></span><span>      <span>"films"</span><span>:</span> <span>[</span><br></span><span>        <span>{</span><br></span><span>          <span>"title"</span><span>:</span> <span>"A New Hope"</span><span>,</span><br></span><span>          <span>"releaseDate"</span><span>:</span> <span>"1977-05-25"</span><br></span><span>        <span>}</span><span>,</span><br></span><span>        <span>{</span><br></span><span>          <span>"title"</span><span>:</span> <span>"The Empire Strikes Back"</span><span>,</span><br></span><span>          <span>"releaseDate"</span><span>:</span> <span>"1980-05-17"</span><br></span><span>        <span>}</span><br></span><span>      <span>]</span><br></span><span>    <span>}</span><br></span><span>  <span>}</span><br></span><span><span>}</span><br></span></code></pre>

总结

这是对 GraphQL 查询获取用法的简要介绍,变体的原理实际上与查询相同,即传递查询和变量。在复杂的项目中,你应该使用 GraphQL 客户端,如 Apollo、Relay 或其他。

当你需要将项目规模保持在最低限度时,获取具有重要作用。Axios 也是一种很好的获取方式。使用获取时,请务必考虑浏览器支持。