Graphql

变更操作

学习如何在NestJS中创建和配置GraphQL变更操作,包括代码优先和模式优先两种方法

变更操作

在GraphQL中,变更用于修改服务器端数据(即读取、写入和删除数据)。变更的结构和语法与查询相同,但它们必须以mutation关键字开头。Apollo文档提供了关于变更的优秀概述。

代码优先

让我们添加另一个方法到我们的AuthorResolver中,用于创建新的作者(createAuthor)。

@Mutation(returns => Author)
async createAuthor(@Args('createAuthorInput') createAuthorInput: CreateAuthorInput) {
  return this.authorsService.create(createAuthorInput);
}

提示 所有装饰器(例如,@Resolver@ResolveField@Args等)都从@nestjs/graphql包中导出。

上面的代码将在SDL中生成以下GraphQL模式的部分:

type Mutation {
  createAuthor(createAuthorInput: CreateAuthorInput!): Author!
}

createAuthor()方法接受一个CreateAuthorInput对象作为参数。CreateAuthorInput是一个输入类型。输入类型与对象类型的不同之处在于它们的用途。输入类型用作参数,而对象类型可以作为返回类型返回。要定义输入类型,请使用@InputType()装饰器。

import { InputType, Field } from '@nestjs/graphql';

@InputType()
export class CreateAuthorInput {
  @Field()
  firstName: string;

  @Field()
  lastName: string;
}

提示 同样,由于TypeScript的元数据反射系统的限制,您必须使用@Field()装饰器手动指示类型和可选性,或使用CLI插件

@ObjectType()一样,@Field()装饰器接受可选的类型函数和选项对象,包括以下属性:

  • nullable:用于指定字段是否可空
  • description:用于设置字段描述
  • deprecationReason:用于将字段标记为已弃用
  • defaultValue:用于设置默认值

例如:

@Field({ description: `作者的名字`, deprecationReason: '在v2模式中不再有用' })
firstName: string;

上面的代码将在SDL中生成以下部分:

input CreateAuthorInput {
  firstName: String! @deprecated(reason: "在v2模式中不再有用")
  lastName: String!
}

模式优先

让我们扩展我们在前一节中使用的模式。

type Author {
  id: Int!
  firstName: String
  lastName: String
  posts: [Post]
}

type Post {
  id: Int!
  title: String!
  votes: Int
}

type Query {
  author(id: Int!): Author
}

type Mutation {
  createAuthor(createAuthorInput: CreateAuthorInput!): Author!
}

input CreateAuthorInput {
  firstName: String!
  lastName: String!
}

现在让我们创建一个解析器方法来处理变更。

@Mutation('createAuthor')
async create(@Args('createAuthorInput') createAuthorInput: CreateAuthorInput) {
  return this.authorsService.create(createAuthorInput);
}

上面的create()方法将接受一个CreateAuthorInput对象作为参数。

类型定义

如果我们使用模式优先方法,我们还需要创建相应的TypeScript定义。

export class CreateAuthorInput {
  firstName: string;
  lastName: string;
}

我们可以通过启用自动生成TypeScript定义来减少冗余工作(如前一章所示)。自动生成的类型如下所示:

export class CreateAuthorInput {
  firstName: string;
  lastName: string;
}

验证

无论您使用代码优先还是模式优先方法,您都可以利用验证装饰器。对于代码优先方法,在输入类型类上使用验证装饰器:

import { IsEmail, IsNotEmpty, IsOptional } from 'class-validator';
import { InputType, Field } from '@nestjs/graphql';

@InputType()
export class CreateAuthorInput {
  @Field()
  @IsNotEmpty()
  @IsEmail()
  email: string;

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

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

注意 要启用GraphQL参数的自动验证,您必须设置ValidationPipe。在这里这里阅读更多关于验证的信息。

对于模式优先方法,您需要扩展自动生成的类:

import { IsEmail, IsNotEmpty, IsOptional } from 'class-validator';
import { CreateAuthorInput } from '../../graphql.ts';

export class CreateAuthorInputDto extends CreateAuthorInput {
  @IsNotEmpty()
  @IsEmail()
  email: string;

  @IsOptional()
  firstName?: string;

  @IsOptional()
  lastName?: string;
}

然后在解析器中使用DTO而不是自动生成的CreateAuthorInput类:

@Mutation('createAuthor')
async create(@Args('createAuthorInput') createAuthorInput: CreateAuthorInputDto) {
  return this.authorsService.create(createAuthorInput);
}