Mutations
In GraphQL, we use mutations to modify server-side data (read more here). The official Apollo documentation uses an upvotePost() mutation example. This mutation implements a method to increase a post's votes property value. To create an equivalent mutation in Nest, we'll make use of the @Mutation() decorator.
Schema first#
Let's extend our AuthorResolver used in the previous section (see resolvers).
@Resolver('Author')
export class AuthorResolver {
constructor(
private readonly authorsService: AuthorsService,
private readonly postsService: PostsService,
) {}
@Query('author')
async getAuthor(@Args('id') id: number) {
return this.authorsService.findOneById(id);
}
@Mutation()
async upvotePost(@Args('postId') postId: number) {
return this.postsService.upvoteById({ id: postId });
}
@ResolveProperty('posts')
async getPosts(@Parent() { id }) {
return this.postsService.findAll({ authorId: id });
}
}Note that we assumed above that the business logic has been moved to the PostsService (querying the post and incrementing its votes property).
Type definitions#
The last step is to add our mutation to the existing types definition.
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
}The upvotePost(postId: Int!): Post mutation is now available to be called as part of our application's GraphQL API.
Code first#
Let's add another method to the AuthorResolver used in the previous section (see resolvers).
@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 this.authorsService.findOneById(id);
}
@Mutation(returns => Post)
async upvotePost(@Args({ name: 'postId', type: () => Int }) postId: number) {
return this.postsService.upvoteById({ id: postId });
}
@ResolveProperty('posts')
async getPosts(@Parent() author) {
const { id } = author;
return this.postsService.findAll({ authorId: id });
}
}The upvotePost() method takes postId (Int) as an argument and returns an updated Post entity. For the reasons explained in the resolvers section, we have to explicitly set the expected type.
If the mutation needs to take an object as an argument, we can create an input type.
@InputType()
export class UpvotePostInput {
@Field() postId: number;
}Hint Both@InputType()and@Field()are imported from thetype-graphqlpackage.
We can then use this type in the resolver class:
@Mutation(returns => Post)
async upvotePost(
@Args('upvotePostData') upvotePostData: UpvotePostInput,
) {}