Apollo Federation指令
Apollo Federation特定GraphQL指令的参考
Apollo Federation定义了一组指令,您可以在您的子图模式中使用这些指令以启用某些功能。
导入指令
要在Federation 2子图模式中使用联邦指令,将以下格式的@link指令应用于schema类型:@link
指令的以下格式应用于schema
类型:
extend schema@link(url: "https://specs.apollo.dev/federation/v2.3",import: ["@key", "@shareable"])
如果您有一个现有的schema声明,则可以应用此指令,或者应用新的extend schema
声明(如上图所示)。
修改import
数组以包含你的子图模式所需的任何联盟指令。上面的例子中导入的是@key
和@shareable
指令(这些是最常用的)。
💡 提示
确保在指令名称中包含@
符号。
重命名指令
如果导入的指令的默认名称与你的自定义指令之一相匹配,你可以使用以下语法重命名导入的指令:
extend schema@link(url: "https://specs.apollo.dev/federation/v2.3",import: [{ name: "@key", as: "@uniqueKey"}, "@shareable"])
此例子图模式使用@uniqueKey
用于联盟指令(通常名为@key
)。
命名空间指令
如果你没有从链接的规范中导入特定的指令,你仍然可以在你的子图模式中使用该指令。然而,该指令具有前缀:
extend schema@link(url: "https://specs.apollo.dev/federation/v2.3",import: ["@key"])type Book @federation__shareable {title: String!}
在上面的例子中,@shareable
没有从联盟规范中导入。因此,它以@federation__shareable
的形式可用。
导入的@link
指令的默认命名空间前缀是其关联规范(通过url
的倒数第二个组件指示)的名称,加两个下划线(__
)。对于 Apollo Federation 指令,此前缀是federation__
。
你可以通过为@link
提供参数来自定义特定规范的命名空间前缀:
extend schema@link(url: "https://specs.apollo.dev/federation/v2.3",as: "fed")type Book @fed__shareable {title: String!}
如图所示,自定义命名空间前缀以两个下划线结束。
@link
指令因为2.0
directive @link(url: String!,as: String,for: link__Purpose,import: [link__Import]) repeatable on SCHEMA
此指令将外部规范的定义链接到此模式。每个 Federation 2 子图都使用@link
指令来导入本文中描述的其它联盟特定指令(参见导入指令中的语法)。
有关更多关于@link
的信息,请参阅官方规范。
管理类型
@key
因为1.0
directive @key(fields: FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE
指定一个对象类型为一个实体并指定其键字段。键字段是一组子图可以使用以唯一标识实体的任何实例的字段。
type Product @key(fields: "id") {id: ID!name: String!price: Int}
如果您使用的子图库支持可重复指令,则可以为单个实体应用多个 @key
指令以指定多个有效的键字段集:
type Product @key(fields: "upc") @key(fields: "sku") {upc: ID!sku: ID!name: String}
ⓘ 注意
要检查您的子图库是否支持可重复指令,请参阅 repeatable @key
项,位置在 Federation 兼容子图实现。
在 Apollo Federation 2.3 及更高版本中,您还可以将 @key
应用到 interface
定义中来创建 实体接口。如果在 Federation 2 的早期版本中将 @key
应用到 interface
上,会发生 组合 错误。
参数
名称 类型 | 描述 |
---|---|
| 必填。GPU 作为字符串提供的 实体 的唯一键贡献的 字段集。 示例
|
| 如果 通常,在 引用实体而不贡献字段时,将此参数设置为 默认值是 |
接口对象
因为2.3
directive @interfaceObject on OBJECT
表示一个对象定义是一个子图实体的接口抽象。这种抽象使子图能够自动向实现特定实体接口的所有实体贡献字段。
在构成过程中,每个@interfaceObject
的字段既被添加到其相应的接口
定义中,也被添加到实现该接口的所有实体类型中。
@extends
因为1.0
directive @extends on OBJECT | INTERFACE
表示一个对象或接口定义是该类型另一个定义的扩展。
⚠️ 注意
如果你的子图库支持GraphQL内置的extend
关键字,请不要使用此指令。相反,使用extend
。
此指令用于与不支持extend
关键字,且通常通过程序生成其模式而不是使用静态.graphql
文件的GraphQL子图库一起使用。
ⓘ 注意
Federation 2不需要使用扩展类型。
在Federation 1中,每个子图都必须扩展Query
和Mutation
类型(如果它们定义了这些类型),并且实体在定义它们的每个子图中扩展,除了它们的原始子图。
管理共享字段
@shareable
因为2.0
directive @shareable repeatable on FIELD_DEFINITION | OBJECT
ⓘ 注意
@shareable
仅在v2.2及以后版本中可重复。
表示允许多个子图解析对象类型的字段(默认情况下,Federation 2中,对象字段只能由一个子图解析)。
type Position {x: Int! @shareabley: Int! @shareable}
如果应用于对象类型定义,则该类型的所有字段都视为@shareable
:
type Position @shareable {x: Int!y: Int!}
如果一个字段在某个子图中标记了@shareable
,则必须在每个定义该字段的Federation 2子图中将其标记为@shareable
或@external
。
ⓘ 注意
如果一个Federation 2超图包含一个Federation 1子图,则Federation 1子图中的所有值类型都会被Federation 2组合算法自动视为@shareable
。
如果一个 字段 包含在实体的 @key
指令 中,那么该字段自动被认为是 @shareable
并且相应的子图(s)中不需要该指令。
另请参阅 Apollo Federation 中的值类型 以及 解析另一个子图的字段。
关于 @shareable
指令,它用于指示一个对象 字段 可以被多个 子图 解析。由于接口字段不是直接解析的(它们的实现是), @shareable 在接口字段上没有意义,并且不允许(至少从联盟 2.2 版起;早期联盟版本错误地在接口字段上忽略了 @shareable
)。
@inaccessible
因为2.0
directive @inaccessible on FIELD_DEFINITION | INTERFACE | OBJECT | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION
指示子图模式中的定义应从路由器的 API 模式 中省略,即使该定义也存在于其他子图。这意味着该字段根本不会暴露给客户端。
使用 @inaccessible
的常见用例包括:
ⓘ 注意
与大多数指令不同,合成图模式 保留了此指令的使用。有关保留其他指令的信息,请参阅 @composeDirective
。
因此,如果您 重命名此指令,则必须在每个子图中使用相同的名称。否则,由于名称不匹配,将发生组合错误。
type Position @shareable {x: Int!y: Int!z: Int! @inaccessible}
type Position @shareable {x: Int!y: Int!# Subgraph is not yet updated}
通常,当您在某个子图中添加一个附加值类型字段时,组合将失败,因为该字段在其他子图中不可解析。使用 @inaccessible
,您可以在将字段添加到其他子图中时保留组合。当推广完成时,您可以删除指令并开始使用该字段。
一个不可访问的字段或类型未被省略在图模式中,因此路由器仍然知道它的存在(但客户端不能将其包括在 操作)。这使得路由器可以在组合来自多个子图的实体字段时,使用不可访问的字段作为实体 @key
的一部分。
如果一个类型被标记为 @inaccessible
,则必须将该类型返回的所有字段也标记为 @inaccessible
。否则,将发生组合错误。
有关更多信息,请参阅 使用 @inaccessible
。
@override
因为2.0
directive @override(from: String!) on FIELD_DEFINITION
表明一个对象字段现在由该子图而不是另一个已定义的子图解析。这使得您可以迁移一个字段从一个子图到另一个子图。
您可以将 @override
应用于 实体字段 以及根 操作 类型(如 Query
和 Mutation
)的字段。
type Product @key(fields: "id") {id: ID!inStock: Boolean!}
type Product @key(fields: "id") {id: ID!inStock: Boolean! @override(from: "Products")}
在上面的例子中,我们将 Product.inStock
字段从产品 子图迁移到库存子图。组合的图模式显示,即使在产品子图中也定义了该字段,但 Product.inStock 的解决是通过库存子图而非产品子图。
您可以将 @override
应用到 @shareable
字段。如果这样做,则只有一个提供的子图的 from
参数不再解析该字段。其他子图仍然可以解析该字段。
只能有一个子图可以 @override
某个给定的字段。如果多个子图尝试 @override
相同字段,则发生组合错误。
有关更多信息,请参阅 迁移实体和根字段。
渐进式 @override
因为2.7
在生产 subgraph 上推出任何更改,包括字段迁移,可能会降低图的表现。一次性将所有流量从一个 subgraph 转到另一个 subgraph 可能会超载覆盖 subgraph。
渐进式 @override
特性允许以渐进式、逐步部署带有 @override 字段的 subgraph。作为 subgraph 开发者,您可以为覆盖和被覆盖 subgraph 对字段各自解决流量比例进行自定义。您可以为 @override 字段应用标签以设置应该由覆盖 subgraph 解决的流量百分比,其余部分由被覆盖的 subgraph 解决。然后您可以在 Studio 中监控 subgraph 的性能,解决问题,并迭代地逐步增加百分比,直到所有流量都被覆盖 subgraph 解决。
有关更多信息,请参阅 使用 @override 的增量迁移指南。。
参数
名称 类型 | 描述 |
---|---|
| 必需。不再解决字段的另一个 subgraph 的名称。
|
| 此参数在 Apollo Federation 2.7 及以后版本中可用。它是 GraphOS 路由器的一个 企业特性,需要组织订阅 GraphOS 企业计划。您可以通过注册免费的企业版进行测试。 可选。任意参数。本版本中支持: |
控制访问
@authenticated
因为2.5
此指令是GraphOS Router的企业功能,需要具有GraphOS企业计划的组织。如果您的组织没有企业计划,可以通过注册企业试用进行测试。
directive @authenticated onFIELD_DEFINITION| OBJECT| INTERFACE| SCALAR| ENUM
表示目标元素仅供身份验证的超级图用户访问。欲了解更多精确访问控制,请参阅下面的@requiresScopes
指令。有关更多详细信息,请参阅路由器文章
@requiresScopes
因为2.5
此指令是GraphOS Router的企业功能,需要具有GraphOS企业计划的组织。如果您的组织没有企业计划,可以通过注册企业试用进行测试。
directive @requiresScopes(scopes: [[federation__Scope!]!]!) onFIELD_DEFINITION| OBJECT| INTERFACE| SCALAR| ENUM
表示目标元素仅供拥有适当JWT权限范围的已验证超级图用户访问。有关更多细节,请参阅路由器文章
参数
名称 类型 | 描述 |
---|---|
| 必需。列出需要授予用户以访问相关元素数据的JWT权限范围。 |
@policy
因为2.6
此指令是GraphOS Router的企业功能,需要具有GraphOS企业计划的组织。如果您的组织没有企业计划,可以通过注册企业试用进行测试。
directive @policy(policies: [[federation__Policy!]!]!) on| FIELD_DEFINITION| OBJECT| INTERFACE| SCALAR| ENUM
表示目标元素基于在Rahi脚本或协处理器中评估的授权策略进行限制。有关更多详细说明,请参阅路由器文章
参数
名称 类型 | 描述 |
---|---|
| 必需。列出要评估的授权策略。 |
引用外部字段
@external
因为1.0
directive @external on FIELD_DEFINITION | OBJECT
表示该子图通常无法解析特定对象的字段,但仍然需要为了其他目的定义该字段。
该指令总是与引用对象字段的另一个指令结合使用,例如@provides
或@requires
type Product @key(fields: "id") {id: ID!name: String! @externalinStock: Boolean!}type Query {outOfStockProducts: [Product!]! @provides(fields: "name")discontinuedProducts: [Product!]!}
本示例 子图 通常无法解析 Product.name
字段,但它可以在 Query.outOfStockProducts
查询 路径(由 @provides
指令 指示)解析这些字段。
如果应用于一个 对象类型 定义,该类型的所有 字段 都被视为 @external
:
type Position @external {x: Int!y: Int!}
@provides
因为1.0
directive @provides(fields: FieldSet!) on FIELD_DEFINITION
指定一组 实体字段,子图可以解析,但仅限于特定的模式路径(在其他路径上,子图无法解析这些字段)。
如果一个 子图始终可以解析特定的实体字段,请不要使用此指令。
使用此 指令始终是一个可选项优化。它可以减少路由器需要与之通信以解决某些操作的总子图数,从而提高性能。
type Product @key(fields: "id") {id: ID!name: String! @externalinStock: Boolean!}type Query {outOfStockProducts: [Product!]! @provides(fields: "name")discontinuedProducts: [Product!]!}
此示例子图可以解析 Query.outOfStockProducts
返回的产品的 Product.name
,但不能解析 Query.discontinuedProducts
。
ⓘ 注意
如果一个 子图 @provides
一个实体字段:
- 该子图必须定义该字段并标记为
@external
,如上所示使用Product.name
。 - 实体字段必须在每个定义它的子图中被标记为
@shareable
或@external
。 - 实体字段必须在至少另一个子图中标记为
@shareable
(即至少有一个子图始终可以解析该字段)。
否则,会发生 组成错误。
有关更多信息,请参阅 使用 @provides
。
参数
名称 类型 | 描述 |
---|---|
| 必需的。 一个 GraphQL 选择集(以字符串形式提供)的对象字段和子字段,子图只能在此查询路径上解决。 示例
|
@requires
因为1.0
directive @requires(fields: FieldSet!) on FIELD_DEFINITION
表示特定实体字段的解析器依赖于由其他子图解析的其他实体字段的值。这告知路由器需要首先获取那些外部定义字段的值,即使原始客户端查询没有请求它们。
type Product @key(fields: "id") {id: ID!size: Int @externalweight: Int @externalshippingEstimate: String @requires(fields: "size weight")}
上面示例子图解析了Product
对象的shippingEstimate
字段,但它需要产品的size
和weight
来执行此操作。由于这两个字段由不同的子图解析,它们被标记为@external
。
ⓘ 注意
如果一个子图使用@requires
实体字段,该子图必须定义该字段并将其标记为@external
,如上例中的Product.size
和Product.weight
所示。否则,将发生组合错误。
另请参阅贡献计算实体字段。
参数
名称 类型 | 描述 |
---|---|
| 必需。一个GraphQL选择集(以字符串形式提供)包含此字段所需的@external对象字段和子字段。 示例
|
应用元数据
@tag
因为1.1
directive @tag(name: String!) repeatable on FIELD_DEFINITION | INTERFACE | OBJECT | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA
将任意字符串元数据应用到模式位置。自定义工具可以在模式交付流程的任何步骤中使用此元数据,包括组合、静态分析和文档。GraphOS Enterprise的合约功能使用@tag及其包括和排除过滤器。
ⓘ 注意
与其他指令不同,组合会保留在生成的超级图模式中对此指令的使用。要保留其他指令的使用,请参阅@composeDirective。
因此,如果您重命名此指令,您必须在每个使用它的子图中使用相同的名称。否则,由于命名不匹配,将发生组合错误。
extend schema@link(url: "https://specs.apollo.dev/federation/v2.3", import: ["@tag"])type Query {customer(id: String!): Customer @tag(name: "team-customers")employee(id: String!): Employee @tag(name: "team-admin")}interface User @tag(name: "team-accounts") {id: String!name: String!}type Customer implements User @tag(name: "team-customers") {id: String!name: String!}type Employee implements User @tag(name: "team-admin") {id: String!name: String!ssn: String!}
参数
名称 类型 | 描述 |
---|---|
| 必需。要应用的模式名称。 |
管理自定义指令
@composeDirective
因为2.1
directive @composeDirective(name: String!) repeatable on SCHEMA
指示组合将子图模式中特定自定义类型系统指令的所有使用情况都保留在超级图模式中(默认情况下,组合从超级图模式中省略大多数指令)。
⚠️ 注意
不要与 可执行指令 一起使用。可执行指令在组合上有不同的规则。
extend schema@link(url: "https://specs.apollo.dev/link/v1.0")@link(url: "https://specs.apollo.dev/federation/v2.3", import: ["@composeDirective"])@link(url: "https://myspecs.dev/myDirective/v1.0", import: ["@myDirective", { name: "@anotherDirective", as: "@hello" }])@composeDirective(name: "@myDirective")@composeDirective(name: "@hello")directive @myDirective(a: String!) on FIELD_DEFINITIONdirective @hello on FIELD_DEFINITION
此指令有以下要求:
- 确保您的 子图库 支持
@composeDirective
或尝试手动将@composeDirective
定义添加到您的子图模式中。 - 必须通过
@link
指令从核心规范导入,并定义和导入必须保留的指令。 - 指定的
name
必须与在此子图中用于指令的名称匹配。- 如果您在
@link
定义中使用了as
参数以修改指令的名称,从规范默认名称变为修改后的名称,提供修改后的名称,而不是默认名称。
- 如果您在
- 如果多个子图导入和使用该指令:
- 所有这些子图使用的指令名称必须相同。
- 所有这些子图应使用由指令定义的同一主要版本的规范。
如果上述要求有任何一项未满足,组合 将失败。
如果不同的子图使用了指令对应规范的不同的版本,则超图模式使用所有子图中版本号码最高的版本。 组合 将不会验证此版本的指令是否与使用较早版本的子图兼容。
参数
名称 类型 | 描述 |
---|---|
| 必需。 保留的组合中指令的名称(包括前缀 |
使用上下文保存和引用数据
@context
因为2.8
此功能仅在 GraphOS 企业计划.
中可用。 你可以通过报名参加免费的.
企业试用版
directive @context(name: String!) on OBJECT | INTERFACE | UNION;
@context 指令定义了一个命名上下文,从该上下文中可以传递到一个带有 @fromContext
指令的字段接收器注解的字段。接收器必须是一个带有注解的字段 @fromContext
。
每个 @context
都必须用名称进行定义,并且每个 @context
名称可以应用于子图内部的多个位置。例如:
type A @key(fields: "id") @context(name: "userContext") {id: ID!prop: String!}type B @key(fields: "id") @context(name: "userContext") {id: ID!prop: String!}type U @key(fields: "id") {id: ID!field (arg: String @fromContext(field: "$userContext { prop }")): String!}
@fromContext
因为2.8
此功能仅在 GraphOS 企业计划.
中可用。 你可以通过报名参加免费的.
The @fromContext
指令用于设置从哪获取注解字段的值。该上下文必须已经使用 @context
指令进行了定义。
scalar ContextFieldValue;directive @fromContext(field: ContextFieldValue) on ARGUMENT_DEFINITION;
在字段上必须使用 @fromContext
指令作为参数。其字段值——ContextFieldValue
(标量)——必须包含定义的上下文名称和从上下文类型中选择字段的选项。
在 @fromContext
的 ContextFieldValue
中使用的选择语法类似于 GraphQL 字段选择语法,但有一些附加规则:
- 第一个元素必须是使用
@context
定义的一个上下文名称,前面加上$
(例如,$myContext
)。这是唯一可以被注解字段引用的上下文。 - 不能使用
@skip
和@include
指令。 - 第二个元素必须是一个选择集,它可以解析为单个字段。
- 顶层数据类型条件不得相互重叠,以便字段可以解析为单个值。
- 在
ContextFieldValue
中引用的所有字段必须都在当前子图中表达。如果字段跨越多个子图引用,它们必须带有@external
注释。 - 参数必须为可空。因为是按子图级进行验证,所以当合并子图时(比如当一个字段在一个子图中为可空,而在另一个子图中不可空时),所引用的字段可能会变成可空的。
当在多个地方设置相同的上下文值时,ContextFieldValue
必须将每个位置的每个类型解析为一个单一值,该值与参数类型相匹配。
有关使用 @context
和 @fromContext
的示例,请参阅 使用上下文在类型层级共享数据。