概述
我们已经了解到 模式检查和 发布如何在我们的开发流程中发挥作用,以及当流程顺利进行且不产生任何错误时会发生什么。现在是时候解决不那么顺利的情况了,当针对 子图进行更改时会出现 组合错误。
在本课程中,我们将
- 了解 超级图 组合中通常遇到的错误类型
- 了解如何在 composition 中导航 错误
- 了解如何使用
@inaccessible
directive
更新子图
让我们回到我们的子图团队,他们正在努力改进 Airlock。 👩🏽🚀 账户团队的阿喀琉斯刚刚对 accounts
subgraph的 schema 进行了一些更改,以显示主机的星系坐标。
在 schema 中,他们定义了团队商定的 GalacticCoordinates
类型,并包含了两个 fields:纬度和经度。
type GalacticCoordinates {latitude: Float!longitude: Float!}
(你是不是已经发现错误了?别担心,我们马上就会讲到的!记住,本课的重点是当事情 不在第一时间起作用时会发生什么!)
他们还在 field中添加了一个新的 Host
entity: coordinates
,它返回 GalacticCoordinates
类型。
type Host implements User @key(fields: "id") {#... other Host fields"Where the host is primarily located"coordinates: GalacticCoordinates}
随着这些新 schema 的增加,我们准备帮助阿喀琉斯发布这些更改,并将此功能推广到世界各地。按照我们在上一课中介绍的过程,列表中的第一件事是使用 Rover运行本地 schema 检查。
我们将打开一个新的终端窗口,并针对 Airlock 的 staging
variant运行 rover subgraph check
命令,其中包括文件路径和 subgraph名称参数为 accounts
schema。
rover subgraph check airlock-managed-fed@staging \--schema "accounts.graphql" \--name accounts
我们看到这里面有些不对劲!下面是我们在终端中看到的错误信息
Checking the proposed schema for subgraph accounts against airlock-managed-fed@stagingerror[E029]: Encountered 2 build errors while trying to build subgraph "accounts" into supergraph "airlock-managed-fed@staging".Caused by:Encountered 2 build errors while trying to build the supergraph.INVALID_FIELD_SHARING: Non-shareable field "GalacticCoordinates.latitude" is resolved from multiple subgraphs: it is resolved from subgraphs "accounts" and "listings" and defined as non-shareable in subgraph "accounts"INVALID_FIELD_SHARING: Non-shareable field "GalacticCoordinates.longitude" is resolved from multiple subgraphs: it is resolved from subgraphs "accounts" and "listings" and defined as non-shareable in subgraph "accounts"The changes in the schema you proposed for subgraph accounts are incompatible with supergraph airlock-managed-fed@staging. See https://apollo.graphql.net.cn/docs/federation/errors/ for more information on resolving build errors.
错误表明 GalacticCoordinates
字段 (latitude
和 longitude
) 在 accounts
和 listings
子图 中都解析过了,但它们在 accounts
子图 中被定义为不可共享的。这是 Achilles 正在研究的子图!
他们忘记给类型定义添加 @shareable
指令,所以让我们确保添加它。
type GalacticCoordinates @shareable {latitude: Float!longitude: Float!}
Achilles 更新了他们的架构,当我们再次运行 rover subgraph check
命令时,可以看到这个修正已经解决了 组合 错误!
Checking the proposed schema for subgraph accounts against airlock-managed-fed@stagingCheck Result:Compared 1 schema changes against 13 operations┌────────┬─────────────┬───────────────────────────────────────────────┐│ Change │ Code │ Description │├────────┼─────────────┼───────────────────────────────────────────────┤│ PASS │ FIELD_ADDED │ type `Host`: field `coordinates` added │└────────┴─────────────┴───────────────────────────────────────────────┘View full details at https://studio.apollographql.com/graph/airlock-managed-fed/operationsCheck/{URL}
Achilles 继续处理他们的 子图,添加必要的 解析器 和 数据源 方法来实现他们的架构添加。
添加新的共享字段
在将他们的更改推送到代码库之前,Achilles 会见了 Airlock 团队并得知项目模型设计已更新!除了数值坐标,用户还想了解位置的本地名称。例如,比起“83.0405 纬度和 35.2034 经度”,客人更容易理解“Z 星球”(但他们也需要知道精确坐标)。
Achilles 向 字段 中添加了新的 GalacticCoordinates
类型: nickname
,可返回 String
。
type GalacticCoordinates @shareable {latitude: Float!longitude: Float!nickname: String}
太棒了!此新 字段 已通过 AccountsAPI
服务返回,因而在 解析程序 或 数据源 文件中无需进行其他更改。Achilles 非常期待推出此功能,他们忘记在本地再次运行 rover subgraph check
命令。相反,他们直接将更改推送到 GitHub 代码库并创建一个 PR。此操作会触发 Schema Checks 作业。
糟了,该作业失败了!
不要担心,这意味着我们的管道在问题到达生产之前就捕获到了错误!我们可以通过访问 PR 中嵌入的链接,转到 Studio 的 Checks 页面来确切调查作业失败的原因。
GraphOS 中的架构检查
Studio 中的 Checks 页面向我们展示了架构检查的结果,以便我们可以诊断错误所在。
GraphOS识明子图组成的失败点,并表明过程中出现问题的点。由于失败的合成意味着未生成新的超级图模式,GraphOS 路由将继续根据其现有有效版本的超级图模式处理请求。因此,即使在 Accounts 团队的变更不起作用的情况下,客户端使用staging
版本的图也不会发生任何错误!这给予 Accounts 团队一个机会来查看错误并在合并其 PR 之前进行修复。
以下是我们看到的错误
error[E029]: Encountered 1 build error while trying to build subgraph "accounts" into supergraph "airlock-managed-fed@staging".Caused by:Encountered 1 build error while trying to build the supergraph.SATISFIABILITY_ERROR: The following supergraph API query:mutation {updateListing(listingId: "<any id>", listing: {}) {listing {coordinates {nickname}}}}cannot be satisfied by the subgraphs because:- from subgraph "listings":- cannot find field "GalacticCoordinates.nickname".- cannot move to subgraph "accounts", which has field "GalacticCoordinates.nickname", because type "GalacticCoordinates" has no @key defined in subgraph "accounts".
我们将进一步调查错误。
在尝试编译超级图模式时,我们遇到了SATISFIABILITY_ERROR
。此错误意味着,表面上我们的子图可能看似兼容,但结果超级图API 将至少包含一项子图无法满足的操作。
错误消息提供了一个示例操作以及两点原因来解释我们的子图无法满足它的原因:
首先,listings
子图找不到 字段 GalacticCoordinates.nickname
。Achilles 仅将 nickname
字段添加到 accounts
子图(其团队负责管理的子图)。listings
子图没有此类 字段。
其次,listings
子图无法将解析 nickname
字段的职责传递给 accounts
子图,因为 GalacticCoordinates
并非 实体,而是一种 值类型。请记住,只有实体(具有 @key
指令的类型)才能在多个 子图中解析不同的 字段。
值类型的 字段可能在不同 子图中的表现形式有所差异,但我们不能 省略 共享 字段。我们需要将这个 GalacticCoordinates.nickname
字段同时添加到 accounts
和 listings
子图中。
注意:你可以详细了解共享 字段在值类型中呈现不同表现形式的各种方法,请参考 Apollo 共享类型文档。
为了将 字段逐步添加到我们的各个 子图中 而不破坏 合成,我们可以使用 @inaccessible
指令。
@inaccessible
指令
该 @inaccessible
指令应用于 字段在 子图模式中。每当它存在于字段上,组合便会将该字段从 路由的 API 模式中省略。这意味着客户端无法在 操作中包含该字段。这有助于我们 递增向多个 子图添加 字段,而不会中断 组合。
请注意,我们只需要将 @inaccessible
指令应用于定义 其中一个 子图,该 字段在其中被定义。
我们来使用 @inaccessible
指令向 GalacticCoordinates
值类型中递增添加 nickname
字段。计划如下:
👩🏽🚀 在 accounts
子图中:
- Achilles 将添加
GalacticCoordinates.nickname
字段并使用@inaccessible
指令。 - 我们将使用自动化 CI/CD 流程,以确保这些模式添加已进入注册中心的
staging
变量。
👩🏽🏫 然后,在 listings
子图中:
- Lisa 将添加
GalacticCoordinates.nickname
字段。我们不需要应用@inaccessible
,因为它已在accounts
子图中解决。 - 我们将使用自动化 CI/CD 流程,以确保这些模式添加已进入注册中心的
staging
变量。
👩🏽🚀使用所有使用值类型的子图中添加的新共享字段,我们最终可以返回到 accounts
子图:
- Achilles 将 删除
@inaccessible
指令从GalacticCoordinates.nickname
字段。这允许该字段包含在 组合中并成功组合,这是因为listings
子图现在包含nickname
字段。 - 我们将使用自动化 CI/CD 流程,以确保这些模式添加已进入注册中心的
staging
变量。
让我们开始吧!
使用 @inaccessible
指令
👩🏽🚀 在 accounts
子图中,Achilles 将在 @inaccessible
指令之后添加 nickname
字段的返回类型。
type GalacticCoordinates @shareable {latitude: Float!longitude: Float!nickname: String @inaccessible}
Achilles 还需要确保已在架构顶部的 指令中包含 import
数组。
extend schema@link(url: "https://specs.apollo.dev/federation/v2.7"import: ["@key", "@shareable", "@inaccessible"])
就是这样!通过这些架构更改,让我们尝试运行本地架构检查。
rover subgraph check airlock-managed-fed@staging \--schema "./accounts.graphql" \--name accounts
在终端中,我们将看到
Checking the proposed schema for subgraph accounts against airlock-managed-fed@stagingCompared 1 schema changes against 16 operations┌────────┬─────────────┬────────────────────────────────────────┐│ Change │ Code │ Description │├────────┼─────────────┼────────────────────────────────────────┤│ PASS │ FIELD_ADDED │ type `Host`: field `coordinates` added │└────────┴─────────────┴────────────────────────────────────────┘
太棒了,检查通过,没有错误!添加的 nickname
字段未显示在检查中,这是因为它当前被标记为 @inaccessible
。我们将向 GitHub 推送更改,并让 CI 运行其 架构检查。当这些检查通过时,我们可以合并 PR,自动触发部署过程,并将更改部署到 accounts
子图在 Heroku 中的暂存环境,以及 Apollo 模式注册表中的 Airlock 图 staging
变体。
将新的共享字段添加到 listings
子图
👩🏽🏫 返回 listings
子图,Lisa 会向 GalacticCoordinates
值类型添加 nickname
字段。
type GalacticCoordinates @shareable {latitude: Float!longitude: Float!nickname: String}
此新 字段已由 ListingsAPI
服务返回,因此 解析器 或 数据源 文件中无需进行任何其他更改。我们可以遵循 CI/CD 进程,将这些模式更改提交到 listings
子图 在 Heroku 中的暂存环境以及 Apollo 模式注册表中的 Airlock 图表 暂存 变量!
删除 @inaccessible
指令
👩🏽🚀 由于 GalacticCoordinates.nickname
字段 在每个使用值类型的 子图 中定义,Achilles 已准备好从 GalacticCoordinates.nickname
字段 中删除 @inaccessible
指令。
type GalacticCoordinates @shareable {latitude: Float!longitude: Float!nickname: String}
就是这样!现在,我们可以遵循我们已经习惯的 CI/CD 进程,并将这些模式更改提交到 暂存!
这次模式检查将显示 nickname
字段 已成功添加:
Checking the proposed schema for subgraph accounts against airlock-managed-fed@stagingCompared 1 schema changes against 16 operations┌────────┬─────────────┬────────────────────────────────────────────────────┐│ Change │ Code │ Description │├────────┼─────────────┼────────────────────────────────────────────────────┤│ PASS │ FIELD_ADDED │ type `GalacticCoordinates`: field `nickname` added │└────────┴─────────────┴────────────────────────────────────────────────────┘
在验证暂存环境中的所有内容正常后,我们就可以部署到生产环境了!我们在前面的课程中已经介绍了这些步骤,因此如果你需要复习,可以随时参考该部分内容。
我们通过向坐标添加一个熟悉的昵称来改进了 Galactic Coordinates 项目。此功能已正式面向世界发布,客户端即可使用!
实践
关键要点
- 我们使用
rover subgraph check
命令执行 架构检查 本地。 - 架构检查 的输出可以在 Studio 中查看,也可以使用 Rover CLI 在本地查看。
- 要向值类型添加一个新的 字段,我们应首先将
@inaccessible
指令 应用到 字段。然后,我们可以将新字段逐步添加到定义值类型的每个 子图。最后,我们可以删除@inaccessible
指令 和 字段 将正式成为 超级图架构 的一部分。
下一步
在下一课中,我们将学习 操作 检查,以及 GraphOS 如何根据客户端从图形中获取数据的历史方式验证建议的架构更改。
分享你对本课程的问题和评论
你的反馈有助于我们不断改进!如遇困难或对课程内容感到疑惑,请告知我们,我们会帮助你解决问题。所有评论均为公开,必须遵守 Apollo 行为准则。请注意,已解决或已被解决的评论将被移除。
您需要一个 GitHub 帐号才能在下方发帖。没有 GitHub 帐号? 请转到我们的 Odyssey 论坛发帖。