多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
## 指令 一个指令可以被附加在一个字段或对象片段上,并能按照服务器所希望的任何方式影响查询语句的执行(参见[此处](https://graphql.org/learn/queries/#directives))。GraphQL 规范中提供了几个默认的指令: - `@include(if: Boolean)` - 仅在参数为真时,才在结果中包含此字段 - `@skip(if: Boolean)` - 参数为真时,跳过此字段 - `@deprecated(reason: String)` - 标记此字段为已弃用,并附上原因 指令其实就是一个带有 `@` 符号前缀的标识符,可选项为后面紧跟着的命名参数列表,它可以出现在 GraphQL 查询和模式语言中的几乎任何元素之后。 ### 自定义指令 要指示当 Apollo/Mercurius 遇到您的指令时应该发生什么,您可以创建一个转换器函数。 此函数使用 mapSchema 函数遍历架构中的位置(字段定义、类型定义等)并执行相应的转换。 ~~~typescript import { getDirective, MapperKind, mapSchema } from '@graphql-tools/utils'; import { defaultFieldResolver, GraphQLSchema } 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` 转换函数: ~~~typescript GraphQLModule.forRoot({ // ... transformSchema: (schema) => upperDirectiveTransformer(schema, 'upper'), }); ~~~ 一旦注册,`@upper` 指令就可以在我们的模式中使用。 但是,您应用指令的方式将根据您使用的方法(代码优先或模式优先)而有所不同。 ### 代码优先 在代码优先方式中,使用 `@Directive()` 装饰器来应用指令。 ```typescript @Directive('@upper') @Field() title: string; ``` > `@Directive()` 装饰器是从 `@nestjs/graphql` 包里导出的。 指令可以被应用在字段、字段解析器、输入和对象类型上,同样也可以应用在查询、变更和订阅上。这里有一个将指令应用于查询处理层的例子: ```typescript @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 中声明指令,如下所示: ~~~typescript GraphQLModule.forRoot({ // ..., transformSchema: schema => upperDirectiveTransformer(schema, 'upper'), buildSchemaOptions: { directives: [ new GraphQLDirective({ name: 'upper', locations: [DirectiveLocation.FIELD_DEFINITION], }), ], }, }), ~~~ `GraphQLDirective` 和 `DirectiveLocation` 都是从 `graphql` 包中导出的。 ### 架构优先 在架构优先方式中,直接在 SDL 中应用指令。 ```graphql directive @upper on FIELD_DEFINITION type Post { id: Int! title: String! @upper votes: Int } ```