概述
现在是见证联邦真正力量的时候了;我们即将把这些部分组合起来,使我们的查询比以往任何时候都更强大,更具动态性。
在本课中,我们将
- 了解什么是实体 类型,它的用途,以及如何定义它
- 将
Listing
类型转换为一个 实体
评论和列表
还记得我们的梦想 查询 吗?
query GetListingAndReviews {listing(id: "listing-1") {titledescriptionnumOfBedsamenities {namecategory}overallRatingreviews {idtext}}}
正如这个 查询 所示,我们希望 reviews
和 overallRating
成为 字段 在 Listing
类型上。
这最大的问题是什么?正如我们之前讨论过的, reviews
子图 对 listings 中的类型一无所知,更不用说它应该添加一个 Listing
类型了!让我们用实体来解决这个问题。
什么是实体?
一个 实体 是一个 对象类型,它的 字段 分布在多个 子图 上。它是联邦图架构的基本构建块,用于在子图之间连接数据,同时仍然遵守关注点分离原则。
使用 实体 时,每个 子图 可以执行以下一项或两项操作:
- 贡献 不同的 字段 到 实体
- 引用 一个 实体,这意味着在 子图 中定义的另一个 字段 中使用它作为返回值类型。
贡献与引用
为了区分 子图,即那些 贡献 到一个 实体 的,以及那些 引用 一个 实体 的,可以这样理解:一个 子图 贡献 字段 实际上是在从 它自己的域 向 实体 类型添加新的数据功能。
这与仅仅 引用 实体 的 子图 形成对比;它本质上只是“提及”实体的存在,并提供它作为 另一个字段 的返回值类型。
在联邦中,我们使用实体来创建连贯的类型,这些类型不局限于一个 子图 或另一个;相反,它们可以跨越整个 API!
在我们的示例中,我们希望用与评论相关的补充我们的 Listing
类型。这使得 Listing
类型成为一个完美的 实体 候选人;它需要有在 两个 子图 中定义的 字段。这让我们可以构建对 API 中“列表”的更强大的表示,以及构成它的不同数据。
要创建 实体,一个 子图 需要提供两样东西:一个 主键 和一个 引用解析器。
定义主键
一个 实体 的 主键 是 字段(或字段)可以唯一地标识 子图 中该 实体 的一个实例。就像在数据库中一样,这是让我们能够区分 一个事物 与 另一个事物 的信息。当我们谈论列表时,我们使用它们的 id
字段 来识别 哪个 列表是我们正在谈论的。
路由器 使用主键从多个 子图 中收集数据,并将它们与单个 实体 实例关联起来。这就是我们如何知道每个子图都在谈论,并提供数据的 同一个 对象!
我们使用 @key
指令,以及一个名为 fields
的属性来设置我们要用作 实体 主键的 字段。
type EntityType @key(fields: "id") {# ...}
引用解析器和实体表示
因为一个 实体 的 字段 可以跨 子图 分布,因此每个 提供 字段 的子图都需要一种方法来识别 路由器 正在收集数据的实例。当它能够识别此实例时,子图 可以提供其他数据。识别 实体 的特定实例采用一种称为 引用解析器 的方法。
此方法接收一个名为 实体 的基本对象。一个 实体表示 是一个对象, 路由器 用它来识别 实体 的特定实例。表示包含该 类型名称 的 实体 和特定实例的 @key
字段 。
__typename
字段:此 字段 自动存在于所有 GraphQL 类型中。它总是以字符串形式返回其包含类型的名称。例如,Listing.__typename
返回 "Listing"。@key
字段: 子图 可以用来识别 实体 实例的键值对。例如,如果我们使用 "id" 字段 作为主键定义Listing
实体 ,那么我们的实体表示将包含一个 "id" 属性,其值类似于 "listing-3"。
传递给每个 子图 的 实体 表示,用于解决特定 Listing
的 字段 ,可能看起来像这样:
{"__typename": "Listing","id": "listing-3"}
您可以将 实体 表示视为 路由器 需要关联来自多个 子图 的数据的最小基本信息,并确保每个子图都在讨论同一个对象。
正如我们很快将看到的那样,特定清单的 实体 表示将为我们的 reviews
子图 提供它需要的所有信息(不多也不少!),以便贡献相关的评论数据。
创建 Listing
实体
将所有这些都带回到我们梦寐以求的 查询!我们希望将 Listing
类型设置为一个 实体 ,以便 reviews
子图 可以为其贡献两个 字段 :overallRating
和 reviews
。
让我们开始吧!
在 listings
子图中
在您的 rover dev
进程仍在运行的情况下,打开 listings
子图 并导航到 schema.graphqls
。向下滚动以找到 Listing
类型。
在这里,我们将应用 @key
指令 ,传入一个设置为 "id"
的 fields
属性。
type Listing @key(fields: "id") {id: ID!# ... other Listing fields}
当我们保存更改时,rover dev
将自动获取新的模式并重新启动 合成 过程。确保在继续到 reviews
子图 之前它成功合成。
在 reviews
子图中
打开您的代码编辑器以进入 reviews
子图 ,并导航到 src/main/resources/schema/schema.graphqls
文件。我们首先添加 Listing
类型的基本存根:它包含类型名称、@key
指令 以及作为其主键分配的 字段 ,id
。
type Listing @key(fields: "id") {id: ID!}
请注意,我们不包含 任何其他 字段 来自 Listing
实体 (如 listings
子图 中所定义)。我们可以让我们的 reviews
子图 保持干净,并且 只 关注它有责任提供的数据。
让我们将 reviews
字段 添加到 Listing
类型。我们将其返回类型设置为 [Review!]!
。我们还将定义 overallRating
,它返回一个可为空的 Float
类型。
type Listing @key(fields: "id") {id: ID!"The submitted reviews for this listing"reviews: [Review!]!"The overall calculated rating for a listing"overallRating: Float}
测试我们的模式更改
我们的 rover dev
进程应该仍在运行,所以让我们回到 https://127.0.0.1:4000
。
现在,我们将看到 reviews
字段 可用于 Listing
类型。我们的小型模式更改使我们能够构建我们梦寐以求的 查询 !
query GetListingAndReviews {listing(id: "listing-1") {titledescriptionnumOfBedsamenities {namecategory}overallRatingreviews {idtext}}}
虽然看起来很漂亮,但我们的 查询 实际上还不能返回数据。虽然 listings
子图 可以轻松解决 它 的清单 字段 (id
、title
、description
、numOfBeds
和 amenities
),但我们还没有让 reviews
子图 了解 该怎么做 当 路由器 请求特定清单的 reviews
或 overallRating
。
事实上,如果我们运行 查询 ,我们将看到一堆令人讨厌的错误。
练习
将项目从该框拖到上面的空白处
多个
键
引用解析器
只有一个
字段
@primary
路由器
@unique
@key
子图
关键要点
- 一个 实体 是一种可以跨多个 子图 解析其 字段 的类型。
- 要创建 实体,我们可以使用
@key
指令 来指定哪些 字段(或字段组)可以唯一地标识该类型的对象。 - 我们可以以两种方式使用实体
- 作为 字段 的返回类型(引用 实体)。
- 定义 字段 来构建一个 实体(从多个 子图 中获取信息)。
接下来
在下一课中,我们将为我们的 reviews
子图 添加逻辑,使其可以实际返回数据。
分享您关于本课的问题和评论
本课程目前处于
您需要一个 GitHub 帐户才能在下面发布。没有帐户? 请在我们的 Odyssey 论坛中发帖。