迁移到Apollo Federation 2
从Apollo Federation 1升级到Federation 2
📣 如果您还没有,查看Federation 2的新功能。
您可以将(而且应该!)您的Apollo Federation 1 supergraph逐个组件迁移到Federation 2。您的supergraph在迁移过程中的每一步都将按预期工作,即使一些您的子图仍在使用Federation 1的模式。
迁移您的supergraph的每一步都有其自身的好处,因此完成尽可能多的步骤是有用的。您可以随时完成其余部分。
以下是迁移到Federation 2的三个步骤
升级您的网关以支持Federation 2。
您可以选择以下任意一个进行升级
- GraphOS Router,一个高性能的预编译可执行文件(推荐)
- 第2.x版本的
@apollo/gateway
库,以及第4.x版本的Apollo Server
使用Federation 2组合逻辑开始编写您的supergraph 模式。
更新您的单个子图以使用Federation 2功能和指令。
正如所有基础设施更改一样,我们强烈建议在生产环境中执行之前,使用您的supergraph的测试实例完成每一步。
ⓘ 注意
如果您在将supergraph迁移到Federation 2时遇到问题,请在该社区论坛中描述问题。
步骤 1: 升级您的网关
为了让您的 Federation 1 超级图支持 Federation 2,您首先需要将其网关升级到以下之一:
- 的 GraphOS 路由器。这是一个基于 Apollo Router Core 的高性能、预编译的可执行文件,并且与基于 Node.js 的网关相比提供了许多好处。
- 我们建议您迁移到 GraphOS 路由器,除非您已经扩展了 Node.js 网关的功能,而这些功能目前 GraphOS 路由器不支持(这是不常见的)。
- 库的 2.x 版本
@apollo/gateway
,搭配 Apollo Server
ⓘ 注意
GraphOS 路由器和 @apollo/gateway
v2.x 均支持 Federation 1。您可以直接升级而无需对 Federation 1 超级图进行任何其他更改,并且它将按预期工作。
迁移到 GraphOS 路由器
升级 @apollo/gateway
和 Apollo Server
的 @apollo/gateway@apollo/gateway
库支持 Federation 2 超级图模式。从 2.0.0 版本开始,这些版本的 @apollo/gateway 需要 16.0.0 或更高版本的 graphql 库。
您可以使用以下命令在网关项目中安装这些库的更新版本
npm install @apollo/gateway graphql
Apollo Server 3.x 支持这些更新后的库版本,然而 Apollo Server 3.x 已被弃用。因此,我们强烈建议还将您的网关升级到 Apollo Server 4。
- 了解如何迁移到 Apollo Server 4。
- 如果您仍在使用 Apollo Server 2.x,我们建议迁移到 v3.x 然后再迁移到 4.x。
步骤 2:配置您的组合方式
联邦 2 使用一种全新的方法来组合 supergraph 模式表。这种方法与联邦 1 backward compatible,与联邦 1 subgraph 模式表子图兼容,并且即使对于联邦 1 的子图也提供了以下好处:
- 帮助 组合提示当您的子图模式定义不一致时
- 支持实现其他接口的接口(联邦 1 组合不支持)
按照以下说明配置您当前使用的任何组合方式:
在您配置这些更改后,请确保您的路由器正在使用您新创建的Federation 2supergraph模式。 (如果您使用托管联盟,则路由器将自动从Apollo获取新模式。)
您现在使用Federation 2组合来组合Federation 1子图。 最自然的问题接下来是,“这些子图的行为会发生什么变化?” 在下一步操作之前,答案是:没有任何变化!
ⓘ 注意
如果您的supergraph与Federation 2组合不成功,请查阅破坏性更改以了解最常见的原因。
步骤3:更新子图
ⓘ 注意
您可以逐个更新子图。 下面的步骤描述了如何修改单个子图以支持Federation 2,您可以在团队方便的时候为给定的子图执行这些步骤。
Federation 2提供了强大的新功能,需要您修改子图。 这些功能包括:
- 在子图之间选择性共享类型和字段使用
@shareable
- 使用使用
@override
从一个子图安全地迁移字段到另一个子图 - 使用使用
@inaccessible
隐藏内部路由字段,以便用户访问
您所做的模式更改与Federation 1不兼容,这意味着除非恢复这些更改,否则您将无法再使用Federation 1组合。
更新子图库
为了使用新的Federation 2功能和它们相关的指令,更新您的子图库到一个版本,该版本自动支持这些指令是非常有益的。
如果您的子图使用Apollo Server和
@apollo/subgraph
库,则更新@apollo/subgraph
到版本2.0.0
或更高,例如:npm install @apollo/subgraph如果你的子图使用了另一个服务器库,请检查兼容性表以查看它是否支持Federation 2指令。如果支持,请查阅该库的文档,确定需要更新到哪个版本。
- 如果你的库尚不支持Federation 2指令,如果你可以在你的模式中添加自定义指令定义,你仍然可以与Federation 2一起使用这个库!
选择Federation 2
向您的子图模式添加以下定义:
extend schema@link(url: "https://specs.apollo.dev/federation/v2.0",import: ["@key", "@shareable"])
此定义标识了一个模式为Federation 2模式,并且它导入
了模式使用的任何Federation特定指令。没有这个@link
定义,组合
如有必要,添加指令定义
目前,并非所有子图库都为Federation 2指令(如@shareable
)提供内置支持。如果您的库不提供此支持,您需要将以下指令定义添加到您的子图模式中:
ⓘ 注意
一些子图库是“代码优先”的(它们从代码动态生成其模式),而不是“模式优先”(它们使用静态的模式文件)。对于代码优先库,手动添加这些指令定义并不直接。如果您在您的库中遇到这种情况,请通过提交问题。
所有Federation 2指令的定义都可在本文中找到。我们与库维护者合作,帮助尽可能多的子图库自动添加这些模式定义。
标记所有值类型作为@shareable
在Federation 2中默认情况下,大多数架构字段仅通过单个子图可解析。在Federation 1中,对于值类型:
Fed. 1(在Fed. 2中无效)
type Position {x: Int!y: Int!}
type Position {x: Int!y: Int!}
为了在Federation 2中使两个子图解析上述字段,两边的模式中都需要使用@shareable
指令:
Fed. 2
type Position {x: Int! @shareabley: Int! @shareable}
type Position {x: Int! @shareabley: Int! @shareable}
ⓘ 注意
您也可以直接将对类型定义(如上面的Position
)应用@shareable
。这等价于对该类型所有字段的@shareable
应用。
有关更多详细信息,请参阅值类型。
更新实体定义
Federation 2对实体引入了微妙但强大的变化。这些变化需要相应更新您的子图模式中的定义。
移除不必要的语法
在Federation 1中,一个实体起源于一个子图,然后其他子图扩展实体以添加字段:
Fed. 1
type Product @key(fields: "id") {id: ID!name: String!price: Int}
extend type Product @key(fields: "id") {id: ID! @externalinStock: Boolean!}
在Federation 2中,实体不再有一个起源子图。相反,每个子图都可以定义一个实体并为其贡献字段:
Fed. 2
type Product @key(fields: "id") {id: ID!name: String!price: Int}
type Product @key(fields: "id") {id: ID!inStock: Boolean!}
注意上述Federation 2子图中的以下内容:
- 库存子图不再
扩展
Product
实体。 - 库存子图不再将
Product.id
字段标记为@external。 - 即使没有标记为
@shareable
,两个子图都可以解析Product.id
。- 与大多数字段不同,如
Product.id
这样的@key
字段默认是@shareable
。这对于@key
字段是必要的,因为网关使用它们来将来自不同子图的数据关联到同一对象。
- 与大多数字段不同,如
将 @provides
字段标记为 @shareable
与 Federation 1 一样,Federation 2 支持 @provides
指令,以便子图只解析特定查询路径的特定字段。
但是,如果子图为某个特定字段提供支持,则必须在始终可解析的每个子图中将该字段标记为 @shareable
:
Fed. 2
type Product @key(fields: "id") {id: ID!name: String! @shareableprice: Int}
type Product @key(fields: "id") {id: ID!name: String! @externalinStock: Boolean!}type Query {outOfStockProducts: [Product!]! @provides(fields: "name")}
在这里,销售子图中的 Query.outOfStockProducts
提供了 Product.name
字段。因此,该字段必须在第 Products
子图(并在 Federation 1 的销售子图中,与 Federation 1 一样)中标记为 @shareable
,否则将发生组成错误。
修改实体占位符的 @key
在某些情况下,子图引用了没有为它贡献任何字段的实体。在 Federation 1 中,这些情况看起来像以下这样:
Fed. 1
type Product @key(fields: "id") {id: ID!name: String!price: Int}
type Product @key(fields: "id") {id: ID!}type Review {product: Product!score: Int!}
上面的评论子图使用 Product
作为 Review.product
字段的返回类型,因此它需要为 Product
实体定义一个 "占位符"。这个占位符包含足够的信息来识别一个唯一的实例。
在 Federation 2 中,应像这样在占位符的 @key
参数中包含 resolvable: false
,例如:
Fed. 2
type Product @key(fields: "id") {id: ID!name: String!price: Int}
type Product @key(fields: "id", resolvable: false) {id: ID!}type Review {product: Product!score: Int!}
设置 resolvable: false
告知网关子图未为特定实体定义引用解析器。这最常见的是在 引用一个未为其贡献字段的实体 时。
已完成!你应该现在有一个成功地组装并充分利用了新联盟功能的Federation 2 超级图。如果你遇到问题,请通过社区论坛与我们联系。