5. 查询片段
10m

概述

在上节课中,我们学习了如何使用接口来定义在不同类型中共享的常见属性。我们还学习了如何为那些常见属性编写查询。

但当我们尝试为其它对特定实现类型是唯一的时会发生什么?例如,在 Airlock 中,Review.author 返回一个实现User接口的对象,该对象可以是HostGuest。房东和客人有一些他们不会相互共享,例如Host.listingsGuest.funds

我们知道返回接口的可以返回任何实现该接口的。那么我们如何知道返回对象上将有哪些其它

要回答这个问题,我们需要另一个工具:查询片段

在本课中,我们将

  • 了解内联和命名
  • 了解如何 接口以及,使用内联和命名

查询接口的共享字段

我们可以 该字段以与查询其他类型和字段相同的方式返回一个接口。

我们以 query 关键字开头,后跟 的名称,之后是大括号。在大括号内,我们可以查询接口中概述的

我们来看 Airlock 中的示例 。此 使用 me ,该操作返回已登录的 User。我们还要求提供 nameprofilePicture ,它们是 Airlock 用户个人资料页面中显示的详细信息。

query GetMyProfile {
me {
name
profilePicture
}
}

用户个人资料页面还显示其他信息,具体取决于您是房东还是客人。对于房东,我们要显示他们的个人资料描述。对于房客,我们要显示他们钱包中的当前资金数额。

我们无法立即将这些添加到我们的中,因为这些字段属于它们特定的HostGuest类型,并且me 返回User接口。如果我们尝试将funds 添加到我们现有的中,我们将得到一个错误,因为User接口没有funds

附加的角色特定,我们需要使用片段

GraphQL 片段

一个 片段是从中提取的的子集,你可以重复使用它们并在多个 之间共享这些字段。

命名片段

要定义 ,我们从 fragment 关键字开始,然后是 的名称(说明其用途)。然后,我们添加关键字 on,后面是 的关联类型。在大括号内,我们列出该关联类型对应的

fragment HostProfileFields on Host {
profileDescription
}
fragment GuestProfileFields on Guest {
funds
}

要在我们的原始 中使用这些 ,我们将它们包括在我们的 中。我们通过将片段名称前置三个句点(...)来执行此操作,类似于 JavaScript 的扩展语法。

query GetMyProfile {
me {
name
profilePicture
...HostProfileFields
...GuestProfileFields
}
}
fragment HostProfileFields on Host {
profileDescription
}
fragment GuestProfileFields on Guest {
funds
}

注意:您可以在下一部分中的 沙盒中测试此

这些 已命名片段,它们用于在不同的查询之间重用是很方便的。

内联片段

我们还可以用得到类似的内嵌片段。为此,我们将我们中的已命名替换为片段本身的内容,保留我们的三个时期 (...),然后指定类型名称 (on Hoston Guest)。当我们不必在之间重用时,这会很方便。

通过内嵌看起来像这样:

query GetMyProfile {
me {
name
profilePicture
... on Host {
profileDescription
}
... on Guest {
funds
}
}
}

现在,如果登录用户是房东,我们获取其profileDescription,如果登录用户是客人,我们获取其funds。(并且在所有情况下,我们获取用户的nameprofilePicture。)

测试查询

要查看这些起作用,让我们使用 Airlock 测试一些查询

让我们来构建以便使用__typename和内嵌获取个人详细信息。

query GetMyProfile {
me {
__typename
name
profilePicture
... on Host {
profileDescription
}
... on Guest {
funds
}
}
}

现在,让我们测试一下我们的

  1. 打开一个新的浏览器窗口,转到https://127.0.0.1:4000,然后单击按钮在沙盒中您的服务器。

  2. 由于 Airlock 需要认证,我们需要在 Headers 选项卡中添加一个 Authorization标头。将标头值设置为Bearer user-1(适用于主机)或Bearer user-2(适用于访客)。

    Screenshot of GraphOS Studio Explorer. In the Headers tab, there's a header with a key called 'Authorization' and a value of 'Bearer user-1'.
  3. 将以上复制到 Explorer 中并运行。

响应应类似于以下内容之一

我们还可以尝试使用命名的(如下所示)执行相似。我们将获取与内联碎片查询相同的数据!

query GetMyProfile {
me {
__typename
name
profilePicture
...HostProfileFields
...GuestProfileFields
}
}
fragment HostProfileFields on Host {
profileDescription
}
fragment GuestProfileFields on Guest {
funds
}

在 Airlock 代码库中查看

整个在 Airlock 客户端代码中使用了多个。查看以下示例:

  • client/src/utils.js中定义的LISTING_FRAGMENT
  • HostGuest上对GET_USER查询中的内联(在client/src/utils.js中定义)
  • HostUPDATE_PROFILE变异中的内联(在client/src/pages/profile.js中定义)

实践

使用以下架构完成接下来的两个代码挑战

type Query {
availableBooks: [Book]
borrowedBooks(userId: ID!): [Book]
}
interface Book {
isbn: ID!
title: String!
genre: String!
}
type PictureBook implements Book {
isbn: ID!
title: String!
genre: String!
numberOfPictures: Int
isInColor: Boolean
}
type YoungAdultNovel implements Book {
isbn: ID!
title: String!
genre: String!
wordCount: Int
numberOfChapters: Int
}
代码挑战!

通过声明两个已命名碎片来完成以下查询。一个名为 PictureBookFields 位于 PictureBook 类型上,用于检索 numberOfPicturesisInColor 的字段。另一个名为 YANovelFields 位于 YoungAdultNovel 类型上,用于检索 wordCountnumberOfChapters 的字段。在 GetAvailableBooks 查询中使用这些已命名的碎片。

代码挑战!

修改以下查询以使用内联碎片。

要点

  • 片段,通常用于多个查询和
  • 接口及其实现类型,我们需要使用命名或内联
    • 命名可以独立存在,非常适合在多个查询中重复使用。
    • 内联可以在中轻松编写和读取。

结论

干得好,您已了解了四个新的概念,您可以在设计自己的架构时使用它们!

如果您有兴趣更深入地了解本侧任务中涵盖的主题,请查看以下附加资源列表。

至于下一步,您可以查看身份验证和授权侧任务,或深入了解Voyage 系列以了解如何使用模块化您的

附加资源

前一页