指令
配置GraphQL类型、字段和参数
一个指令用于装饰 GraphQL 架构或操作的操作以额外的配置。像Apollo Server(以及Apollo 客户端)这样的工具可以读取 GraphQL 文档的指令并执行相应的自定义逻辑。
指令前面都有一个@
字符,例如:
type ExampleType {oldField: String @deprecated(reason: "Use `newField`.")newField: String}
此示例展示了@deprecated
指令,它是一个默认指令(即它是 GraphQL 规范的一部分GraphQL specification)。它展示了关于指令的以下信息:
- 指令可以有自己的 参数(在这个例子中是
reason
)。 - 指令出现在它们装饰的对象(在这个例子中是
oldField
字段)的声明之后。
有效位置
每个 指令只能出现在 特定 的位置,这些位置在一个 GraphQL 模式或 操作 中定义。
例如,下面是 GraphQL 规范中 @deprecated
指令的 定义:
directive @deprecated(reason: String = "No longer supported") on FIELD_DEFINITION | ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION | ENUM_VALUE
这表示 @deprecated
可以装饰四个列出位置中的任何一个。同时请注意,其 reason
参数 是可选的,并提供了默认值。下面提供了每个位置的用法示例:
# ARGUMENT_DEFINITION# Note: @deprecated arguments _must_ be optional.directive @withDeprecatedArgs(deprecatedArg: String @deprecated(reason: "Use `newArg`")newArg: String) on FIELDtype MyType {# ARGUMENT_DEFINITION (alternate example on a field's args)fieldWithDeprecatedArgs(name: String @deprecated): String# FIELD_DEFINITIONdeprecatedField: String @deprecated}enum MyEnum {# ENUM_VALUEOLD_VALUE @deprecated(reason: "Use `NEW_VALUE`.")NEW_VALUE}input SomeInputType {nonDeprecated: String# INPUT_FIELD_DEFINITIONdeprecated: String @deprecated}
如果 @deprecated
出现在 GraphQL 文档的其他地方,则会引发错误。
模式指令与操作指令
通常,给定的 指令 只出现在 独占 的 GraphQL 模式 或 独占 的 GraphQL 操作(虽然规范允许这样做,但很少同时出现)。
例如,在 默认指令中,@deprecated
是模式独占指令,而 @skip
和 @include
是操作独占指令。
GraphQL 规范 列出了所有可能的 指令 位置。模式位置列在 TypeSystemDirectiveLocation
下,操作位置列在 ExecutableDirectiveLocation
下。
默认指令
GraphQL 规范 定义以下默认 指令:
指令 | 描述 |
---|---|
@deprecated(reason: String) | 将字段或枚举值的模式定义为已弃用,带有可选的原因。 |
@skip(if: Boolean!) | 如果 true ,则装饰的 field 或 fragment 在操作中不会被 GraphQL 服务器解析。 |
@include(if: Boolean!) | 如果 false ,则装饰的 field 或 fragment 在操作中不会被 GraphQL 服务器解析。 |
自定义指令
⚠️ Apollo Server 不提供 内置 支持 将模式转换为自定义指令的功能。
您的模式可以定义自定义 指令,然后用于装饰模式的其他部分:
# Definitiondirective @uppercase on FIELD_DEFINITIONtype Query {# Usagehello: String @uppercase}
如果您想定义一个自定义模式指令来 转换 可执行模式的行为,并在向 Apollo Server 提供 之前,我们建议使用 @graphql-tools
库。请查看我们的 使用自定义指令转换模式的示例。
在子图中
在使用自定义 指令的程序化图之前,请确保考虑以下事项:
- 如果多个 子图都可以解析特定的字段,则几乎每个子图都应该针对该字段应用一组相同的自定义指令(定义相同)。否则,该字段的行为可能会根据解析它的 哪 个子图而有所不同。
- 因为指令针对的是单个子图,所以技术上不同的子图可以定义具有不同逻辑的相同的指令。如前所述,如果自定义指令在多个子图中用于解析特定字段,则应在子图中以相同的逻辑定义相同的指令。 组合过程中不会检测或警告此类不一致。
- 组合过程对待 可执行的(客户端)和类型系统(服务器端)指令 的方式不同:
- 如果一个可执行 指令被组合到超级图模式中,那么:
- 所有子图都定义了相同的指令。
- 该指令未包含在任何
@composeDirective
指令中。
- 类型系统 指令不是组合到 路由器的,但它们可以通过@composeDirective指令提供信息。
- 如果一个可执行 指令被组合到超级图模式中,那么:
转换函数
正如我们的示例所示,在Apollo Server 3和4中,您可以为每个子图模式的自定义指令定义一个转换函数。
要将转换函数应用到可执行的子图模式,您首先像平常一样使用buildSubgraphSchema
生成子图模式:
let subgraphSchema = buildSubgraphSchema({ typeDefs, resolvers });
将转换函数应用于所有转换函数后,您可以像平常一样将最终的子图模式提供给ApolloServer
构造函数:
// Transformer function for an @upper directivesubgraphSchema = upperDirectiveTransformer(subgraphSchema, 'upper');
在应用所有转换函数后,您将最终的子图模式作为参数传递给ApolloServer
构造函数,就像您之前做的那样:
const server = new ApolloServer({schema: subgraphSchema,// ...other options...});