本章仅适用于代码优先方法。
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
类,如下所示:
@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 插件,可以简单地声明上述类定义:
@ObjectType()
export class Author {
@Field(type => ID)
id: number
firstName?: string
lastName?: string
posts: Post[]
}
该插件会根据抽象语法树动态添加适当的装饰器。因此,您不必费力处理散布在整个代码中的 @Field
装饰器。
该插件将自动生成任何缺失的 GraphQL 属性,但如果您需要覆盖它们,只需通过 @Field()
明确设置它们即可。
Comments introspection
启用注释自省功能后,CLI 插件将根据注释为字段生成描述。
例如,给出一个示例 roles
属性:
/**
* A list of user's roles
*/
@Field(() => [String], {
description: `A list of user's roles`
})
roles: string[];
您必须复制描述值。启用 introspectComments
后,CLI 插件可以提取这些注释并自动为属性提供描述。现在,上述字段可以简单地声明如下:
/**
* A list of user's roles
*/
roles: string[];
使用 CLI 插件
要启用该插件,请打开 nest-cli.json
(如果您使用 Nest CLI)并添加以下 plugins
配置:
{
"collection": "@nestjs/schematics",
"sourceRoot": "src",
"compilerOptions": {
"plugins": ["@nestjs/graphql"]
}
}
您可以使用 options
属性来自定义插件的行为。
{
"plugins": [
{
"name": "@nestjs/graphql",
"options": {
"typeFileNameSuffix": [".input.ts", ".args.ts"],
"introspectComments": true
}
}
]
}
options
属性必须满足以下接口:
export interface PluginOptions {
typeFileNameSuffix?: string[]
introspectComments?: boolean
}
Option | Default | Description |
---|---|---|
typeFileNameSuffix | ['.input.ts', '.args.ts', '.entity.ts', '.model.ts'] | GraphQL types files suffix |
introspectComments | false | 如果设置为true ,插件将根据注释生成属性的描述 |
如果你不使用 CLI,而是使用自定义的 webpack
配置,则可以将此插件与 ts-loader
结合使用:
getCustomTransformers: (program: any) => ({
before: [require('@nestjs/graphql/plugin').before({}, program)]
}),
SWC 构建器
对于标准设置(非 monorepo),要将 CLI 插件与 SWC 构建器一起使用,您需要启用类型检查,如此处 所述。
$ nest start -b swc --type-check
对于 monorepo 设置,请按照此处 的说明进行操作。
$ npx ts-node src/generate-metadata.ts
# OR npx ts-node apps/{YOUR_APP}/src/generate-metadata.ts
现在,必须通过 GraphQLModule
方法加载序列化元数据文件,如下所示:
import metadata from './metadata'; // <-- file auto-generated by the "PluginMetadataGenerator"
GraphQLModule.forRoot<...>({
..., // other options
metadata,
}),
Integration with ts-jest
(e2e tests)
在启用此插件的情况下运行 e2e 测试时,您可能会遇到编译架构的问题。例如,最常见的错误之一是:
Object type <name> must define one or more fields.
发生这种情况是因为 jest
配置没有在任何地方导入 @nestjs/graphql/plugin
插件。
要解决此问题,请在 e2e 测试目录中创建以下文件:
const transformer = require('@nestjs/graphql/plugin')
module.exports.name = 'nestjs-graphql-transformer'
// 每次更改以下配置时,您都应该更改版本号 - 否则,jest 将无法检测到更改
module.exports.version = 1
module.exports.factory = (cs) => {
return transformer.before(
{
// @nestjs/graphql/plugin 选项(可以为空)
},
cs.program, // `cs.tsCompiler.program`适用于旧版本的 Jest(<= v27)
)
}
完成此操作后,在jest
配置文件中导入 AST 转换器。默认情况下(在启动应用程序中),e2e 测试配置文件位于test
文件夹下,名为jest-e2e.json
。
{
"globals": {
"ts-jest": {
"astTransformers": {
"before": ["<path to the file created above>"]
}
}
}
}
如果您使用jest@^29
,请使用下面的代码片段,因为以前的方法已被弃用。
{
"transform": {
"^.+\\.(t|j)s$": [
"ts-jest",
{
"astTransformers": {
"before": ["<path to the file created above>"]
}
}
]
}
}