概述
是见证联合真正力量的时候了;我们将拼凑各个部分,让我们的查询比以前更加强大且动态。
在此课程中,我们将
- 学习什么实体类型是,它用于什么以及如何定义它
- 将
Listing
类型转换为实体
评论和列表
还记得我们梦想的 查询吗?
query GetListingAndReviews {listing(id: "listing-1") {titledescriptionnumOfBedsamenities {namecategory}overallRatingreviews {idtext}}}
正如 查询所示,我们希望 reviews
和 overallRating
在 fields上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.graphql
。向下滚动找到Listing
类型。
这里,我们将应用@key
指令,传递一个fields
属性,设置为"id"
。
type Listing @key(fields: "id") {id: ID!# ... other Listing fields}
在保存更改后,rover dev
将自动获取新架构并重新启动构图进程。在转到reviews
子图之前,请确保它成功构图了。
在 reviews
子图中
打开代码编辑器转到 reviews
子图,然后导航到 src/schema.graphql
文件。我们首先通过添加 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:4002
。
现在我们将看到 reviews
字段 可在 Listing
类型下使用。我们小巧的架构变更使得构建我们的理想 查询 成为可能!
query GetListingAndReviews {listing(id: "listing-1") {titledescriptionnumOfBedsamenities {namecategory}overallRatingreviews {idtext}}}
虽然我们的 查询 看起来很漂亮,但实际上不能返回数据。尽管 listings
子图 可以轻松解析 其 自己 listing 字段 (id
、title
、description
、numOfBeds
以及 amenities
),但我们尚未告知 reviews
子图 当 何时执行 路由器 请求特定 listing 的 reviews
或 overallRating
。
事实上,如果我们运行 查询,只会看到一堆可怕的错误。
练习
将此框中的内容拖动到上面的空白处
路由器
多个
字段
只能一个
子图
@unique
键
@key
引用解析器
@primary
要点
- 实体是一个能够跨多个子图解析其字段的类型。
- 若要创建实体,可使用
@key
指令指定哪些字段可以唯一标识该类型的一个对象。 - 可以使用实体的两种方式
- 作为字段的返回类型(引用实体)。
- 定义实体的字段来自多个子图(为实体做出贡献)。
接下来
在下一课中,我们将为reviews
子图配备逻辑,以便实际返回数据。
分享你对本课的疑问和评论
本课程当前处于
你需要一个 GitHub 帐户才能在下方发帖。没有帐户? 转而到我们的 Odyssey 论坛发帖。