我们知道我们的数据在哪里,也知道数据的结构。太棒了。现在从我们的解析器!
我们的 GraphQL 服务器 需要访问那个 REST API。它可以使用 fetch
,或者我们可以使用一个名为 DataSource
的便捷帮助类。这个类解决了直接方法中的一些挑战和限制。

为了更好地理解这些挑战和限制,让我们先从 fetch
开始,然后再创建 DataSource
。
在 Node.js 环境中调用 REST API 时,我们可能会使用像 axios
或 node-fetch
这样的库。这些库提供了对 HTTP 方法的轻松访问以及良好的异步行为。
使用 node-fetch
,从我们的 /tracks
端点检索所有曲目,看起来像这样:
fetch("apiUrl/tracks").then(function (response) {// do something with our tracks JSON});
这给了我们曲目数组,但我们仍然缺少作者信息。对于数组中的每个曲目,我们需要调用 /author/:id
端点,如下所示:
fetch(`apiUrl/author/${authorId}`).then(function (response) {// this is the author of our track});
假设我们的 /tracks
端点返回 100 首曲目。那么,我们需要进行一次调用来获取数组,然后进行 100 次额外的调用 来获取每个曲目的作者信息。
现在,如果我们这 100 首曲目都是同一个作者创作的?我们将会进行一次调用来获取曲目,检索我们的 100 首曲目,然后进行 100 次调用来获取完全相同的作者。
听起来效率很低,对吧?我们可以只进行两次调用,而最终却进行了 101 次调用。
这是一个典型的 N+1 问题。“1” 指的是获取顶级 tracks
的调用 字段,而“N” 是获取每个曲目作者子字段的后续调用的次数。
{tracks {# 1titleauthor {# N calls for N tracksname}}}
此外,在我们的应用程序和这个特定的 查询 中,我们并不希望主页频繁变化。也许每隔几周就会添加一首新曲目。利用缓存来避免不必要的 REST API 调用会很好。方便的是,我们的 REST API 已经为其端点设置了缓存头。
对于 GraphQL,一个 查询 通常由来自不同端点、具有不同缓存策略的不同 字段 和类型组成。那么,我们应该如何处理这种情况下缓存呢?

我们开始真正感受到我们简单的 fetch
方法的局限性。
为了解决这些问题,我们需要专门为 GraphQL 设计的工具,它将有效地处理 REST API 调用的资源缓存和重复数据消除。
并且,由于在构建 GraphQL API 时从 REST 中获取数据是一项非常常见的任务,因此,Apollo 提供了一个 专用 的 DataSource
类,专门用于此目的: RESTDataSource
。
通过在服务器上实现 RESTDataSource
,我们刚刚看到的所有挑战都将开箱即用地得到解决。
让我们看看如何在我们的 Catstronauts 应用程序中扩展和实现这个 RESTDataSource
。
分享您关于本课的问题和评论
您的反馈将帮助我们改进!如果您卡住或感到困惑,请告诉我们,我们会帮助您。所有评论都是公开的,必须遵守 Apollo 行为准则。请注意,已解决或已解决的评论可能会被删除。
您需要一个 GitHub 帐户才能在下面发布。没有帐户? 请在我们的 Odyssey 论坛上发布。