概述
在上一课中,我们刚刚看到了如何 子图 可以 引用 一个 实体 作为 字段 的返回类型。现在,让我们来看看如何 子图 可以 贡献 字段 到一个 实体。
在本课中,我们将
- 学习多个 子图 可以如何贡献 字段 到一个 实体
- 更新
Location
实体 在我们的reviews
子图架构 中,通过贡献reviewsForLocation
和overallRating
字段 s
✏️ 贡献字段
记得我们的 FlyBy UI,我们知道它需要获取每个位置的 overallRating
,以及它的 reviewsForLocation
列表:
遵循关注点分离原则,任何关于评分或评论的数据都由 reviews
子图 填充,所以让我们到那里去,进行这些添加!
打开
subgraph-reviews/reviews.graphql
文件。找到
Location
实体 定义在架构中。我们之前将它定义为Location
类型的存根。subgraph-reviews/reviews.graphqltype Location @key(fields: "id", resolvable: false) {id: ID!}默认情况下,子图 应该只贡献 字段,这些字段不是由其他子图定义的,主键字段除外。这意味着,因为
locations
子图 定义了name
、description
和photo
作为 字段 用于Location
类型,我们不会 - 也应该不会 - 在这里定义这些 字段 在reviews
子图 中!注意: 你可以覆盖上面解释的默认行为来 允许多个子图解析同一个字段 通过应用
@shareable
或@provides
指令。这是一个可选的性能优化,可以指示 路由器 如何规划跨越尽可能少的 子图 的 查询 执行。因为我们现在希望
reviews
子图 贡献新的 字段 到Location
定义中,我们需要做的第一件事是从@key
指令 中移除resolvable: false
属性。这将使我们的reviews
子图 能够定义和解析它自己的Location
字段。从
Location
类型的@key
指令 中移除resolvable: false
属性。subgraph-reviews/reviews.graphqltype Location @key(fields: "id") {id: ID!}
✏️ 向 Location 实体添加新字段
现在我们准备好添加两个新的 字段。
- the
overallRating
字段,它返回一个Float
- the
reviewsForLocation
字段,它返回一个非空Review
对象列表。
我们还将向这些 字段 添加描述,以便我们能够快速了解它们所代表的内容。
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]!}
✏️ 添加解析器
这些 字段 中的每一个都需要一个 解析器 函数来返回数据,所以让我们接下来处理它。
打开
resolvers.js
文件,位于subgraph-reviews
目录中。向
resolvers
映射添加一个Location
条目。我们还将为overallRating
和reviewsForLocation
字段 添加两个空的 解析器 函数。subgraph-reviews/resolvers.jsconst resolvers = {Query: {// ...},Location: {overallRating: () => {},reviewsForLocation: () => {},},Review: {// ...},Mutation: {// ...},};我们将从
overallRating
解析器 开始。首先,我们将解构parent
参数 (一个Location
对象)以获取id
字段。我们还将解构contextValue
参数 以提取我们的dataSources
。subgraph-reviews/resolvers.jsoverallRating: ({id}, _, {dataSources}) => {// TODO},在函数内部,我们将返回调用
dataSources
对象、其ReviewsAPI
和其getOverallRatingForLocation
方法的结果。然后,传入我们要 查询 的位置的id
。subgraph-reviews/resolvers.jsoverallRating: ({id}, _, {dataSources}) => {return dataSources.reviewsAPI.getOverallRatingForLocation(id);},注意:你可以通过查看
subgraph-reviews/datasources/ReviewsApi.js
文件,了解getOverallRatingForLocation
方法的工作原理。接下来,我们将为
reviewsForLocation
字段 设置 解析器 函数,并遵循与之前相同的结构。这次,我们将使用ReviewsAPI
的getReviewsForLocation
方法,根据位置的 id 获取该位置的所有评论。subgraph-reviews/resolvers.jsreviewsForLocation: ({id}, _, {dataSources}) => {return dataSources.reviewsAPI.getReviewsForLocation(id);},
太棒了!我们的 解析器 接收位置的 id,并且可以返回该位置的正确数据。
添加一个 __resolveReference
函数
之前,我们了解到每个 子图 对 贡献 字段 的 实体 都需要为该实体定义一个引用 解析器。
我们已经在 locations
子图 中定义了引用 解析器,但 reviews
子图 也需要某种方法来了解它正在为 哪个 特定位置对象解析 字段。
好消息是:因为我们使用的是 Apollo Server,所以不需要在 reviews
子图 中显式地定义引用 解析器 函数。 Apollo Server 为我们没有定义 任何 的实体定义了一个 默认 引用 解析器。
此图表显示了 __resolveReference
函数默认情况下如何通过对特定 Location
的 查询 工作。
- 根据其
id
参数,在locations
子图 中解析查询到的位置。 - 当服务器到达
reviewsForLocation
字段 时,路由器 知道这是reviews
子图 的责任。__resolveReference
函数接收查询到的Location
对象,该对象由locations
子图 返回。 -
reviewsForLocation
解析器 接收引用的Location
对象作为其parent
参数,然后它可以解构并使用它来解析数据。
即使此功能在幕后为我们工作,我们也会在下面的可选部分逐步介绍如何自己添加此函数,并回顾一下当我们的 路由器 在 子图 中关联数据时会发生什么。
那么,我们是否准备好测试我们的 超级图?别着急!请记住,我们做了架构更改!这些更改需要发布到注册表,否则我们会遇到在上一课中遇到的相同问题。
因此,我们将运行 rover subgraph publish
命令,并为其传递我们 reviews
的 子图 的值。
rover subgraph publish <APOLLO_GRAPH_REF> \--name reviews \--schema ./subgraph-reviews/reviews.graphql
跨子图查询数据
发布成功后,让我们回到 Studio 并刷新 Explorer。我们可以看到,我们的子字段 列表现在包括 overallRating
和 reviewsForLocation
!
让我们将这些 字段 包含在一个新的 查询 中,发送到我们的 路由器。我们将使用客户端需要用于位置详细信息页面的查询。
query GetLocationDetails($locationId: ID!) {location(id: $locationId) {idnamedescriptionphotooverallRatingreviewsForLocation {idcommentrating}}}
在 变量 面板中:
{ "locationId": "loc-1" }
看看这些甜蜜的数据!
客户将会很高兴他们能从两个 子图 获取有关位置的信息,而无需自己做任何工作来将它们组合在一起!
更棒的是,我们不需要重启我们的 路由器。这是由于我们的路由器与 Apollo Uplink 的连接。我们新发布的 子图 触发了 GraphOS 来组合一个新的 超级图模式。然后我们的路由器轮询了 Uplink 并获取了新的超级图模式。最棒的是,路由器立即开始使用新的超级图模式,使我们能够 查询 新的 字段!
有了它,我们终于可以勾掉我们模式协议中的最后两个 字段!
练习
将项目从这个框中拖放到上面的空白处
搜索
分配
键字段
创建
端点
实体
类型
上行链路
路由器
删除
关注点
您正在处理一个管理图书信息的联合图。 authors
子图定义了一个 Author
实体,它具有一个主键字段 id
,该字段为不可为空的 ID
类型。您想在 books
子图中使用 Author
实体。在下面定义 Author
实体,并添加一个新字段 books
,它返回一个不可为空的 Book
类型的不可为空列表。
关键要点
- 一个 子图 向 实体 贡献 字段 应该定义以下内容:
- 该 实体,使用
@key
指令 及其主键 字段,以及 子图 定义的新字段 - 一个
__resolveReference
函数,用于了解 子图 为哪个特定 实体 实例解析 字段。这可以通过 Apollo Server 默认处理。
- 该 实体,使用
- 联合架构有助于以应用程序开发人员(或多个开发人员团队!)希望使用数据的方式来组织和说明我们 图 中类型之间的关系。
- 当两个 子图 使用相同的主键来关联类型的数据时, 路由器 会协调来自两个来源的数据,并将它们捆绑在一个响应中。
接下来
恭喜您,您已完成 FlyBy 图 中所有 字段 的实现!
在下一个也是最后一个课程中,我们将把后端和前端组合在一起,最终看到 FlyBy 在浏览器中运行!
分享您对本课程的疑问和评论
您的反馈有助于我们改进!如果您遇到困难或困惑,请告诉我们,我们将帮助您解决。所有评论均公开,必须遵守 Apollo 行为准则。请注意,已解决或已处理的评论可能会被删除。
您需要一个 GitHub 帐户才能在下面发布。没有帐户? 改在我们的 Odyssey 论坛上发布。