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;
}
| Option | Default | Description |
|---|---|---|
typeFileNameSuffix | ['.input.ts', '.args.ts', '.entity.ts', '.model.ts'] | GraphQL types files suffix |
introspectComments | false | If 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>"]
}
}
]
}
}