NestJS Logo

원문을 읽으며 정리합니다.

Table of Contents

  1. Mutations

Mutations

GraphQL의 대부분의 논의는 data fetching에만 초점을 두지만, 완벽한 데이터 플랫폼은 서버 측 데이터도 잘 수정할 수 있어야 한다. REST에서, 모든 요청이 서버에 side-effect를 일으킬 수 있지만, GET 요청에서 데이터를 수정하지 않는 것이 모범 사례다. GraphQL은 유사하다 - 기술적으로 모든 쿼리를 구현하여 data write를 발생시킬 수 있다. 그러나, REST와 마찬가지로, write를 유발하는 모든 작업은 mutation을 통해 명시적으로 전송되어야 한다는 규칙을 지키는 것이 좋다(read more).

공식 Apollo 문서에서 upvotePost() mutation 예제를 사용한다. 이 mutation은 게시글의 votes 속성 값을 증가시키는 메서드를 구현한다. NestJS에서 동일한 뮤테이션을 생성하기 위해, @Mutation() decorator를 사용할 것이다.

Code first

이전 섹션에서 사용한 AuthorsResolver에 또다른 메서드를 추가하자(see resolvers).

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

모든 데코레이터(e.g., @Resolver, @ResolveField, @Args, etc.)는 모두 @nestjs/graphql package에서 export 되었다.

그러면 SDL에서 GraphQL schema의 다음 부분이 생성된다.

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

upvotePost() method는 postId ( Int )를 인자로 갖고 업데이트 된 Post 엔티티를 리턴한다. resolvers section에서 설명했던 이유 때문에, 명시적으로 예상되는 타입을 설정해야 한다.

mutation이 어떤 객체를 인자로 가져야 한다면, input type을 만들 수 있다. input type은 인자로 전달할 수 있는 특별한 종류의 객체 type이다(read more here). input type을 정의하기 위해서, @InputType() decorator를 사용한다.

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

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

@InputType() decorator는 옵션 객체를 인자로 갖는다. 따라서, 예를 들면, input type의 설명을 명시할 수 있다. TypeScript의 metadata reflection system에는 제한이 있기 때문에, @Field decorator를 사용하여 수동으로 type을 나타내거나 CLI plugin을 사용해야 한다.

그런 다음, resolver class에 이런 type을 사용할 수 있다.

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

Schema first

이전 섹션에서 사용한 AuthorsResolver를 확장해 보겠다(see resolvers).

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

위에서 비지니스 로직이 PostsService로 이동했다고 가정하자(post에 쿼리를 하고 votes 속성 증가). PostsSerice안에 로직은 간단하거나 필요에 따라 섬세할 수 있다. 이 예제의 핵심 포인트는 resolver가 어떻게 다른 provider와 상호작용할 수 있는지를 보여주는 것이다.

마지막 단계는 기존 types 정의에 뮤테이션을 추가하는 것이다.

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의 일부로 호출할 수 있다.

Next NestJS GraphQL(4) - Subscriptions
Intro NestJS GraphQL(0) - Intro