概述
现在是时候引入那些让获取架构中数据成为可能的函数了。字段 在我们的架构中。
在本课中,我们将
- 探索什么是 解析器,以及它们接受哪些参数
- 学习如何从 解析器 函数访问 数据源
介绍解析器
一个 解析器 的使命是填充你架构中 字段 的数据。
究竟什么是 解析器? 解析器是一个函数。它与它填充数据的 字段 同名。它可以从任何 数据源 获取数据,然后将这些数据转换为客户端所需的形式。
在src
目录中,我们将从创建一个新的 resolvers.ts
文件开始。
📂 src┣ 📂 datasources┣ 📄 graphql.d.ts┣ 📄 helpers.ts┣ 📄 index.ts┣ 📄 resolvers.ts┗ 📄 schema.graphql
在这个文件中,我们将声明一个 resolvers
常量,暂时将其分配给一个空对象。让我们导出它,因为我们会在我们的服务器配置选项中需要它。
export const resolvers = {};
我们的 resolvers
对象的键将对应于我们架构的类型和 字段。
要为 字段 创建一个 解析器,我们首先需要在 resolvers
对象中添加一个 Query
键。该键的值将是 另一个 包含 featuredListings
键的对象。
export const resolvers = {Query: {featuredListings: () => {},},};
注意我们的 解析器 对象是如何遵循我们架构的结构的? featuredListings
是 Query
类型上的一个 字段,所以我们将其定义为 Query
键上的一个属性。
解析器的形状
我们的 解析器 将如何与我们的 数据源 交互? 这就是解析器参数发挥作用的地方。解析器函数具有一个特定的签名,包含四个可选参数: parent
, args
, contextValue
以及 info
。
featuredListings: (parent, args, contextValue, info) => {},
让我们简单地回顾一下每个参数,以了解它们各自的职责
- parent
parent
是此 字段 父级 解析器 的返回值。在处理解析器链时,这将非常有用。 - args
args
是一个对象,其中包含所有由 GraphQL 操作为 字段 提供的 GraphQL 参数。当 查询 特定项目(例如特定列表而不是 所有 列表)时,在客户端中,我们将使用 查询,并附带一个id
参数,该参数将在服务器端通过此args
参数访问。 - contextValue
contextValue
是一个对象,在为特定操作执行的所有 解析器 中共享。解析器需要此 参数 来共享状态,例如身份验证信息、数据库连接,或者在我们的例子中,共享RESTDataSource
。 - info
info
包含有关操作执行状态的信息,包括 字段 名称、从根节点到字段的路径等等。它不像其他参数那样频繁使用,但在执行更高级的操作(例如在 解析器 级别设置缓存策略)时,它会非常有用。
在本课程中,我们将探索前三个参数,首先从 contextValue
开始,它是第三个位置参数。
在解析器中访问数据源
如上所述, contextValue
是一个在所有 解析器 中共享的对象。解析器就是通过它来访问相同的共享状态,例如 数据源。
让我们通过在 featuredListings
解析器 中添加参数来实际操作一下。
featuredListings: (parent, args, contextValue, info) => {},
这里参数的顺序很重要。如果我们只添加了一个参数,那么函数会将其视为第一个可选参数: parent
。我们需要 contextValue
,它是第三个参数,才能访问我们的 数据源。
我们 不需要 前两个参数,所以按照惯例,我们将它们命名为带下划线的名称:一个下划线表示第一个 (parent
) 以及两个下划线表示第二个 (args
)。对于 contextValue
,我们将对其进行解构,以访问其子对象 dataSources
。并且我们可以省略第四个参数 info
,因为我们不会使用它。
featuredListings: (_, __, { dataSources }) => {},
该 dataSources
属性是 ListingAPI
类实例所在的地方。
访问 ListingAPI
我们将把 ListingAPI
类连接到我们的 GraphQL 服务器 在下一课中。现在,我们将假设 dataSources
将包含一个名为 listingAPI
的属性(按照惯例用小写字母编写,因为它是一个 ListingAPI
类的实例)。我们可以在这里调用该实例的 getFeaturedListings
方法,直接在我们的 解析器 中——该方法将完成其余工作!
Query: {featuredListings: (_, __, { dataSources }) => {return dataSources.listingAPI.getFeaturedListings();},}
提示: 作为最佳实践,在处理您的 解析器 和 数据源 时,尽量使解析器函数尽可能集中。这样做使您的 API 对未来的更改更具弹性。您可以安全地重构数据获取代码,或将来源完全从 REST API 更改为数据库,而不会破坏您的 API。这还使您的解析器更易读,更容易理解,这在您定义越来越多的解析器时非常有用!
现在,您可能会在 IDE 中看到一些红色的波浪线错误。TypeScript 正在抱怨我们为 featuredListings
解析器 提供了许多参数,但我们没有指定它们是什么类型的数据。相反,我们看到几乎所有内容都被推断为 any
类型。
Parameter '_' implicitly has an 'any' type.Parameter '__' implicitly has an 'any' type.Binding element 'dataSources' implicitly has an 'any' type.
让我们在下一课中找出如何修复这些类型错误。
练习
contextValue
参数有什么用?关键要点
- 解析器 是可以为架构中的每个 字段 定义的函数。它们接受四个可选参数,
parent
、args
、contextValue
和info
,它们负责在查询特定 字段 时返回数据。
接下来
我们的 数据源 和 解析器 函数仍然缺少一些东西:类型注释!这意味着我们在代码中看到一些 TypeScript 错误。我们可以手动编写这些类型,但有一种更有效的方法。在下一课中,我们将探讨如何从我们的 GraphQL 架构 生成 TypeScript 类型。
分享您关于本课的问题和评论
本课程目前处于
您需要一个 GitHub 帐户才能在下面发布。没有? 改为在我们的 Odyssey 论坛中发布。