跳到主要内容

Mutations

大多数关于 GraphQL 的讨论都侧重于数据获取,但任何完整的数据平台都需要一种修改服务器端数据的方式。 在 REST 中,任何请求都可能导致对服务器的副作用,但最佳实践建议我们不应该在 GET 请求中修改数据。 GraphQL 类似 - 从技术上讲,任何查询都可以被实现为导致数据写入。 然而,与 REST 一样,建议遵循约定,即任何导致写入的操作都应该通过显式发送变更来完成(在此处阅读更多)。

官方的 Apollo 文档使用了一个 upvotePost() 变更的例子。该变更实现了一个增加帖子投票属性值的方法。 为了在 Nest 中创建一个等效的变更,我们将利用 @Mutation() 装饰器。

代码优先

让我们在上一节中使用的 AuthorResolver 中添加另一个方法(请参阅解析器)。

@Mutation(returns => Post)
async upvotePost(@Args({ name: 'postId', type: () => Int }) postId: number) {
return this.postsService.upvoteById({ id: postId });
}
提示

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

这将导致在 GraphQL 架构中生成以下部分:

type Mutation {
upvotePost(postId: Int!): Post
}

upvotePost() 方法将 postId(Int)作为参数,并返回更新后的 Post 实体。 出于解析器部分解释的原因,我们必须显式设置预期的类型。

如果变更需要将对象作为参数传递,我们可以创建一个输入类型。 输入类型是一种特殊的对象类型, 可以作为参数传递(在此处阅读更多)。 要声明输入类型,请使用 @InputType() 装饰器。

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

@InputType()
export class UpvotePostInput {
@Field()
postId: number;
}
备注

@InputType() 装饰器接受一个选项对象作为参数,因此您可以例如指定输入类型的描述。 请注意,由于 TypeScript 的元数据反射系统的限制,您必须使用 @Field 装饰器手动指定类型, 或者使用一个 CLI 插件

然后我们可以在解析器类中使用此类型:

@Mutation(returns => Post)
async upvotePost(
@Args('upvotePostData') upvotePostData: UpvotePostInput,
) {}

模式优先

让我们扩展上一节中使用的 AuthorResolver(请参阅解析器)。

@Mutation()
async upvotePost(@Args('postId') postId: number) {
return this.postsService.upvoteById({ id: postId });
}

请注意,上面我们假设业务逻辑已经移到了 PostsService(查询帖子并递增其votes属性)。 PostsService 类中的逻辑可以简单或复杂,这个示例的主要目的是展示解析器如何与其他提供程序进行交互。

最后一步是将我们的变更添加到现有类型定义中。

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 的一部分调用。