ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
## 变更(Mutations) 大多数关于 `GraphQL` 的讨论都集中在数据获取上,但任何完整的数据平台也需要一种修改服务器端数据的方法。 在 REST 中,任何请求最终都可能对服务器造成副作用,但最佳实践建议我们不应修改 `GET` 请求中的数据。 `GraphQL` 是类似的——从技术上讲,任何查询都可以实现来导致数据写入。 但是,与 `REST` 一样,建议遵守约定,即任何导致写入的操作都应通过突变显式发送([在这里阅读更多](http://graphql.cn/learn/queries/#mutations)阅读更多内容)。 `Apollo` 官方文档使用 `upvotePost()` 变更示例。 这个变更实现了一种增加帖子投票属性值的方法。 为了在 Nest 中创建等效的突变,我们将使用 `@Mutation() `装饰器。 ### **代码优先** 让我们使用 在上一节中AuthorResolver另一种方法(参见[解析图](https://docs.nestjs.com/graphql/resolvers))。 ```typescript @Resolver(of => Author) export class AuthorResolver { constructor( private readonly authorsService: AuthorsService, private readonly postsService: PostsService, ) {} @Query(returns => Author, { name: 'author' }) async getAuthor(@Args({ name: 'id', type: () => Int }) id: number) { return await this.authorsService.findOneById(id); } @Mutation(returns => Post) async upvotePost(@Args({ name: 'postId', type: () => Int }) postId: number) { return await this.postsService.upvoteById({ id: postId }); } @ResolveProperty('posts') async getPosts(@Parent() author) { const { id } = author; return await this.postsService.findAll({ authorId: id }); } } ``` > 所有装饰器(例如,`@Resolver`、`@ResolveField`、`@Args` 等)都从 `@nestjs/graphql`包中导出。 `upvotePost()` 取 `postId`(`Int`)作为输入参数,并返回更新的 `Post` 实体。出于与解析器部分相同的原因,我们必须明确设置预期类型。 如果突变需要将对象作为参数,我们可以创建一个输入类型。 输入类型是一种特殊的对象类型,可以作为参数传入(在[此处](https://graphql.org/learn/schema/#input-types)阅读更多内容)。 要声明输入类型,请使用 `@InputType()` 装饰器。 ```typescript @InputType() export class UpvotePostInput { @Field() postId: number; } ``` > `@InputType()` 和 `@Field()` 需要从`type-graphql` 包导入。 >`@InputType()` 装饰器将选项对象作为参数,例如,您可以指定输入类型的描述。 请注意,由于 `TypeScript `的元数据反射系统限制,您必须使用 `@Field` 装饰器手动指示类型,或使用 CLI 插件。 然后我们可以在解析器类中使用这种类型: ```typescript @Mutation(returns => Post) async upvotePost( @Args('upvotePostData') upvotePostData: UpvotePostInput, ) {} ``` #### ** 架构优先 ** 让我们扩展我们在上一节中AuthorResolver的用法(见[解析图](https://docs.nestjs.com/graphql/resolvers))。 ```typescript @Resolver('Author') export class AuthorResolver { constructor( private readonly authorsService: AuthorsService, private readonly postsService: PostsService, ) {} @Query('author') async getAuthor(@Args('id') id: number) { return await this.authorsService.findOneById(id); } @Mutation() async upvotePost(@Args('postId') postId: number) { return await this.postsService.upvoteById({ id: postId }); } @ResolveProperty('posts') async getPosts(@Parent() { id }) { return await this.postsService.findAll({ authorId: id }); } } ``` 请注意,我们假设业务逻辑已移至 `PostsService`(分别查询 `post` 和 incrementing `votes` 属性)。 ### 类型定义 最后一步是将我们的变更添加到现有的类型定义中。 ```typescript 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 { upvotePost(postId: Int!): Post } ``` 该 `upvotePost(postId: Int!): Post` 变更现在可以作为我们应用程序的 GraphQL API 的一部分调用。