NestJS 9 GraphQL 中文文档(十四) - 命令行插件

332 阅读4分钟

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

警告 ⚠️
此章节仅适用于代码优先方式

TypeScript的元数据反射系统有一些限制,例如,无法确定类包含哪些属性或识别给定属性是可选的还是必需的。但是,其中一些约束可以在编译时解决。Nest提供了一个增强TypeScript编译过程的插件,以减少所需的模版代码量。

提示 此插件是可配置的。如果你愿意,你可以手动声明所有装饰器,或只在你需要的地方声明特定的装饰器。

概览

GraphQL插件将会自动:

  • 使用@Field注释所有的输入对象、对象类型和参数类属性,除非使用了@HideField
  • 根据问号设置nullable属性(例如:name?: string 将设置 nullable: true
  • 根据type 属性设置类型(同样支持数组)
  • 根据注释生成属性描述(若 introspectComments 设置为 true

请注意,为了能被插件分析到,你的文件名必须具有以下后缀:['.input.ts', '.args.ts', '.entity.ts', '.model.ts'] (例如, author.entity.ts)。如果你使用了其他后缀,你可以通过指定typeFileNameSuffix选项来调整插件的行为(看下文)。

根据我们目前学到的知识,你必须复制大量代码才能让包知道你的类型应该如何在GraphQL中声明。例如,你可以像下面这样定义一个简单的Author类:

// authors/models/author.model.ts
@ObjectType()
export class Author {
  @Field(type => ID)
  id: number;

  @Field({ nullable: true })
  firstName?: string;

  @Field({ nullable: true })
  lastName?: string;

  @Field(type => [Post])
  posts: Post[];
}

虽然对于中型项目来说这不是一个重要问题,但一旦你有了大量的类,它就会变得冗长且难以维护。通过启用GraphQL插件,以上类的定义就可以被简单声明为:

// authors/models/author.model.ts
@ObjectType()
export class Author {
  @Field(type => ID)
  id: number;
  firstName?: string;
  lastName?: string;
  posts: Post[];
}

该插件基于抽象语法树即时添加适当的装饰器。因此,你就不必再为分散在整个代码中的@Field装饰器而苦恼了。

提示
此插件将自动生成任何缺失的GraphQL属性,但是如果你需要覆盖它们,只需用@Field() 显式地设置它们即可。

注释自省

开启注释自省功能后,命令行插件将基于注释生成字段的描述。

例如,在给出的roles属性示例中:

/**
 * A list of user's roles
 */
@Field(() => [String], {
  description: `A list of user's roles`
})
roles: string[];

你必须重复描述的值。但introspectionComments开启后,命令行插件就可以提取这些注释并自动为属性提供描述了。现在,上述字段可以像下面这样简单声明:

/**
 * A list of user's roles
 */
roles: string[];

使用命令行插件

要启用此插件,打开 nest-cli.json(如果你使用 Nest CLI)并添加以下plugins 配置:

{
  "collection": "@nestjs/schematics",
  "sourceRoot": "src",
  "compilerOptions": {
    "plugins": ["@nestjs/graphql"]
  }
}

你可以使用optoins属性来定制插件的行为。

"plugins": [
  {
    "name": "@nestjs/graphql",
    "options": {
      "typeFileNameSuffix": [".input.ts", ".args.ts"],
      "introspectComments": true
    }
  }
]

options属性必须满足以下接口:

export interface PluginOptions {
  typeFileNameSuffix?: string[];
  introspectComments?: boolean;
}
OptionDefaultDescription
typeFileNameSuffix['.input.ts', '.args.ts', '.entity.ts', '.model.ts']GraphQL types files suffix
introspectCommentsfalseIf set to true, plugin will generate descriptions for properties based on comments

如果你不用命令行,而是用一个自定义webpack配置,你可以将此插件与ts-loader结合使用:

getCustomTransformers: (program: any) => ({
  before: [require('@nestjs/graphql/plugin').before({}, program)]
}),

集成ts-jest(e2e 测试)

在启用此插件的情况下运行e2e测试,你可能会遇到编译schema的问题。例如,一个最常见的错误是:

Object type <name> must define one or more fields.

这是因为jest配置没有在任何地方导入@nestjs/graphql/plugin 插件。

要解决此问题,需要在你的端到端测试目录中创建以下文件:

const transformer = require('@nestjs/graphql/plugin');

module.exports.name = 'nestjs-graphql-transformer';
// you should change the version number anytime you change the configuration below - otherwise, jest will not detect changes
module.exports.version = 1;

module.exports.factory = (cs) => {
  return transformer.before(
    {
      // @nestjs/graphql/plugin options (can be empty)
    },
    cs.program, // "cs.tsCompiler.program" for older versions of Jest (<= v27)
  );
};

有了这个文件,然后在你的jest配置文件中导入AST转换器。默认情况下(在初始应用程序中),端到端测试配置文件在test文件夹下且名为jest-e2e.json

{
  ... // other configuration
  "globals": {
    "ts-jest": {
      "astTransformers": {
        "before": ["<path to the file created above>"]
      }
    }
  }
}

如果你使用jest@^29,则要使用以下代码片段,因为之前的方法已经被废弃掉了。

{
  ... // other configuration
  "transform": {
    "^.+\.(t|j)s$": [
      "ts-jest",
      {
        "astTransformers": {
          "before": ["<path to the file created above>"]
        }
      }
    ]
  }
}