NestJS 9 GraphQL 中文文档(七) - 指令

122 阅读2分钟

写在前面的话

Nest 最新的版本为V9,较之前的V7/8有不小改动,GraphQL 部分官方文档之前的V8也是本人翻译的,有很多不完善的地方,这次打算重新精细翻译一遍,会持续更新这块内容,并最后贡献给中文文档仓库,为中文社区贡献一份力量。有兴趣的小伙伴记得要关注收藏。

指令可以被附加到字段或者代码片段,并且可以以服务器期望的任何方式影响查询的执行(在此阅读更多)。GraphQL规范中提供了几个默认指令:

  • @include(if: Boolean) - 如果参数为真,则仅在结果中包含此字段
  • @skip(if: Boolean) - 如果参数为真,则跳过该字段
  • @deprecated(reason: String) - 使用备注将字段标记为已弃用

指令是一种标识符,前面有一个@符号,后面可以选择跟一个命名参数列表,它可以出现在GraphQL查询会和schema语言中的几乎任何元素之后。

自定义指令

为了说明当Apollo/Mercurius遇到你的指令时发生了什么,你可以创建一个转换器函数。该函数使用mapSchema函数遍历shcema中的位置(字段定义、类型定义等)并执行相应的转换。

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转换函数:

GraphQLModule.forRoot({
  // ...
  transformSchema: (schema) => upperDirectiveTransformer(schema, 'upper'),
});

一旦注册后,@upper指令就可以被用在我们的schema中了。但是,你应用指令的方法将根据你使用的方式(代码优先或模式优先)而有所不同。