指令可以附加到字段或片段包含,并且可以以服务器所需的任何方式影响查询的执行(阅读更多信息,请点击此处](https://graphql.org/learn/queries/#directives))。GraphQL 规范提供了几个默认指令:
@include(if: Boolean)
- 仅当参数为真时才在结果中包含此字段@skip(if: Boolean)
- 如果参数为真,则跳过此字段@deprecated(reason: String)
- 使用消息将字段标记为已弃用
指令是一个标识符,前面带有 @
字符,后面可以跟着命名参数列表,它可以出现在 GraphQL 查询和模式语言中的几乎任何元素之后。
自定义指令
要指示当 Apollo/Mercurius 遇到您的指令时应该发生什么,您可以创建一个转换器函数。该函数使用 mapSchema
函数遍历模式中的位置(字段定义、类型定义等)并执行相应的转换。
ts
import { MapperKind, getDirective, mapSchema } from '@graphql-tools/utils'
import { GraphQLSchema, defaultFieldResolver } from 'graphql'
export function upperDirectiveTransformer(
schema: GraphQLSchema,
directiveName: string,
) {
return mapSchema(schema, {
[MapperKind.OBJECT_FIELD]: (fieldConfig) => {
const upperDirective = getDirective(
schema,
fieldConfig,
directiveName,
)?.[0]
if (upperDirective) {
const { resolve = defaultFieldResolver } = fieldConfig
// Replace the original resolver with a function that *first* calls
// the original resolver, then converts its result to upper case
fieldConfig.resolve = async function (source, args, context, info) {
const result = await resolve(source, args, context, info)
if (typeof result === 'string') {
return result.toUpperCase()
}
return result
}
return fieldConfig
}
},
})
}
现在,使用 transformSchema
函数在 GraphQLModule#forRoot
方法中应用 upperDirectiveTransformer
转换函数:
ts
GraphQLModule.forRoot({
// ...
transformSchema: schema => upperDirectiveTransformer(schema, 'upper'),
})
注册后,@upper
指令即可在我们的架构中使用。但是,应用指令的方式将根据您使用的方法(代码优先或架构优先)而有所不同。
代码优先
在代码优先方法中,使用 @Directive()
装饰器来应用指令。
ts
@Directive('@upper')
@Field()
title: string;
@Directive()
装饰器从 @nestjs/graphql
包中导出。
指令可应用于字段、字段解析器、输入和对象类型,以及查询、突变和订阅。以下是在查询处理程序级别应用的指令示例:
ts
@Directive('@deprecated(reason: "This query will be removed in the next version")')
@Query(returns => Author, { name: 'author' })
async getAuthor(@Args({ name: 'id', type: () => Int }) id: number) {
return this.authorsService.findOneById(id);
}
通过 @Directive()
装饰器应用的指令不会反映在生成的架构定义文件中。
最后,确保在 GraphQLModule
中声明指令,如下所示:
ts
GraphQLModule.forRoot({
// ...,
transformSchema: schema => upperDirectiveTransformer(schema, 'upper'),
buildSchemaOptions: {
directives: [
new GraphQLDirective({
name: 'upper',
locations: [DirectiveLocation.FIELD_DEFINITION],
}),
],
},
})
GraphQLDirective
和 DirectiveLocation
均从 graphql
包中导出。
架构优先
在 schema 优先方法中,直接在 SDL 中应用指令。
graphql
directive @upper on FIELD_DEFINITION
type Post {
id: Int!
title: String! @upper
votes: Int
}