13. 为实体贡献
5m

概述

在上一课中,我们刚刚看到了如何 可以 引用 一个 作为 的返回类型。现在,让我们来看看如何 可以 贡献 到一个

在本课中,我们将

  • 学习多个 可以如何贡献 到一个
  • 更新Location 在我们的 reviews 中,通过贡献 reviewsForLocationoverallRating s
The FlyBy schema diagram, with pencil icons next to the Location.reviews and Location.overallRating fields

✏️ 贡献字段

记得我们的 FlyBy UI,我们知道它需要获取每个位置的 overallRating,以及它的 reviewsForLocation 列表:

A query containing fields that will be populated by our two subgraphs, locations and reviews

遵循关注点分离原则,任何关于评分或评论的数据都由 reviews 填充,所以让我们到那里去,进行这些添加!

  1. 打开 subgraph-reviews/reviews.graphql 文件。

  2. 找到 Location 定义在架构中。我们之前将它定义为 Location 类型的存根。

    subgraph-reviews/reviews.graphql
    type Location @key(fields: "id", resolvable: false) {
    id: ID!
    }

    默认情况下, 应该只贡献 ,这些字段不是由其他子图定义的,主键字段除外。这意味着,因为 locations 定义了 namedescriptionphoto 作为 用于 Location 类型,我们不会 - 也应该不会 - 在这里定义这些 reviews 中!

    注意: 你可以覆盖上面解释的默认行为来 允许多个子图解析同一个字段 通过应用 @shareable@provides 。这是一个可选的性能优化,可以指示 如何规划跨越尽可能少的 执行。

    因为我们现在希望 reviews 贡献新的 Location 定义中,我们需要做的第一件事是从 @key 中移除 resolvable: false 属性。这将使我们的 reviews 能够定义和解析它自己的 Location

  3. Location 类型的 @key 中移除 resolvable: false 属性。

    subgraph-reviews/reviews.graphql
    type Location @key(fields: "id") {
    id: ID!
    }
任务!

✏️ 向 Location 实体添加新字段

现在我们准备好添加两个新的

  • the overallRating ,它返回一个 Float
  • the reviewsForLocation ,它返回一个非空 Review 对象列表。

我们还将向这些 添加描述,以便我们能够快速了解它们所代表的内容。

subgraph-reviews/reviews.graphql
type Location @key(fields: "id") {
id: ID!
"The calculated overall rating based on all reviews"
overallRating: Float
"All submitted reviews about this location"
reviewsForLocation: [Review]!
}

✏️ 添加解析器

这些 中的每一个都需要一个 函数来返回数据,所以让我们接下来处理它。

  1. 打开 resolvers.js 文件,位于 subgraph-reviews 目录中。

  2. resolvers 映射添加一个 Location 条目。我们还将为 overallRatingreviewsForLocation 添加两个空的 函数。

    subgraph-reviews/resolvers.js
    const resolvers = {
    Query: {
    // ...
    },
    Location: {
    overallRating: () => {},
    reviewsForLocation: () => {},
    },
    Review: {
    // ...
    },
    Mutation: {
    // ...
    },
    };
  3. 我们将从 overallRating 开始。首先,我们将解构 parent (一个 Location 对象)以获取 id 。我们还将解构 contextValue 以提取我们的 dataSources

    subgraph-reviews/resolvers.js
    overallRating: ({id}, _, {dataSources}) => {
    // TODO
    },
  4. 在函数内部,我们将返回调用 dataSources 对象、其 ReviewsAPI 和其 getOverallRatingForLocation 方法的结果。然后,传入我们要 的位置的 id

    subgraph-reviews/resolvers.js
    overallRating: ({id}, _, {dataSources}) => {
    return dataSources.reviewsAPI.getOverallRatingForLocation(id);
    },

    注意:你可以通过查看 subgraph-reviews/datasources/ReviewsApi.js 文件,了解 getOverallRatingForLocation 方法的工作原理。

  5. 接下来,我们将为 reviewsForLocation 设置 函数,并遵循与之前相同的结构。这次,我们将使用 ReviewsAPIgetReviewsForLocation 方法,根据位置的 id 获取该位置的所有评论。

    subgraph-reviews/resolvers.js
    reviewsForLocation: ({id}, _, {dataSources}) => {
    return dataSources.reviewsAPI.getReviewsForLocation(id);
    },

太棒了!我们的 接收位置的 id,并且可以返回该位置的正确数据。

添加一个 __resolveReference 函数

之前,我们了解到每个 贡献 都需要为该实体定义一个引用

我们已经在 locations 中定义了引用 ,但 reviews 也需要某种方法来了解它正在为 哪个 特定位置对象解析

好消息是:因为我们使用的是 ,所以不需要在 reviews 中显式地定义引用 函数。 为我们没有定义 任何 的实体定义了一个 默认 引用

此图表显示了 __resolveReference 函数默认情况下如何通过对特定 Location 工作。

The reviews subgraph resolve reference function called for a particular queried Location
  1. 根据其 id ,在 locations 中解析查询到的位置。
  2. 当服务器到达 reviewsForLocation 时, 知道这是 reviews 的责任。 __resolveReference 函数接收查询到的 Location 对象,该对象由 locations 返回。
  3. reviewsForLocation 接收引用的 Location 对象作为其 parent ,然后它可以解构并使用它来解析数据。

即使此功能在幕后为我们工作,我们也会在下面的可选部分逐步介绍如何自己添加此函数,并回顾一下当我们的 中关联数据时会发生什么。

那么,我们是否准备好测试我们的 ?别着急!请记住,我们做了架构更改!这些更改需要发布到注册表,否则我们会遇到在上一课中遇到的相同问题。

因此,我们将运行 rover subgraph publish 命令,并为其传递我们 reviews 的值。

rover subgraph publish <APOLLO_GRAPH_REF> \
--name reviews \
--schema ./subgraph-reviews/reviews.graphql

跨子图查询数据

发布成功后,让我们回到 Studio 并刷新 Explorer。我们可以看到,我们的子 列表现在包括 overallRatingreviewsForLocation

studio.apollographql.com/graph/flyby/explorer?variant=current
The Location type with reviews fields

让我们将这些 包含在一个新的 中,发送到我们的 。我们将使用客户端需要用于位置详细信息页面的查询。

query GetLocationDetails($locationId: ID!) {
location(id: $locationId) {
id
name
description
photo
overallRating
reviewsForLocation {
id
comment
rating
}
}
}

变量 面板中:

{ "locationId": "loc-1" }

看看这些甜蜜的数据!

客户将会很高兴他们能从两个 获取有关位置的信息,而无需自己做任何工作来将它们组合在一起!

更棒的是,我们不需要重启我们的 。这是由于我们的路由器与 Apollo Uplink 的连接。我们新发布的 触发了 来组合一个新的 。然后我们的路由器轮询了 Uplink 并获取了新的超级图模式。最棒的是,路由器立即开始使用新的超级图模式,使我们能够 新的

有了它,我们终于可以勾掉我们模式协议中的最后两个

The FlyBy schema diagram, with all the fields checked off!

练习

检查你的理解!
在联合图中,我们应该根据以下内容定义子图: 
 
而不是 
 
. 包含可以在多个子图中解析的字段的类型被称为 
 
. 这些类型始终具有 
 
 ,它使不同的子图能够将数据与同一对象关联起来。为了保持其超级图模式的最新状态,我们的 
 
 可以轮询 
 
.

将项目从这个框中拖放到上面的空白处

  • 分配

  • 键字段

  • 创建

  • 端点

  • 实体

  • 类型

  • 路由器

  • 删除

  • 关注点

代码挑战!

您正在处理一个管理图书信息的联合图。 authors 子图定义了一个 Author 实体,它具有一个主键字段 id,该字段为不可为空的 ID 类型。您想在 books 子图中使用 Author 实体。在下面定义 Author 实体,并添加一个新字段 books,它返回一个不可为空的 Book 类型的不可为空列表。

关键要点

  • 一个 贡献 应该定义以下内容:
    • ,使用 @key 及其主键 ,以及 定义的新字段
    • 一个 __resolveReference 函数,用于了解 为哪个特定 实例解析 。这可以通过 默认处理。
  • 联合架构有助于以应用程序开发人员(或多个开发人员团队!)希望使用数据的方式来组织和说明我们 中类型之间的关系。
  • 当两个 使用相同的主键来关联类型的数据时, 会协调来自两个来源的数据,并将它们捆绑在一个响应中。

接下来

恭喜您,您已完成 FlyBy 中所有 的实现!

在下一个也是最后一个课程中,我们将把后端和前端组合在一起,最终看到 FlyBy 在浏览器中运行!

上一页

分享您对本课程的疑问和评论

您的反馈有助于我们改进!如果您遇到困难或困惑,请告诉我们,我们将帮助您解决。所有评论均公开,必须遵守 Apollo 行为准则。请注意,已解决或已处理的评论可能会被删除。

您需要一个 GitHub 帐户才能在下面发布。没有帐户? 改在我们的 Odyssey 论坛上发布。