• 본 시리즈에서는 How to GraphQL의 Tutorial 문서들을 차례대로 번역합니다.
  • 본 시리즈는 GraphQL Basic and Advanced 시리즈에서 이어집니다. GraphQL을 처음 접하는 분들은 해당 시리즈를 먼저 읽고 오시는 것을 추천드립니다.
  • 이 글은 GraphQL-Node Tutorial - A Simple Mutation을 번역한 글입니다.
  • 오역 또는 의역이 있을 수 있습니다. 양해 부탁드리며, 수정할 필요한 부분은 댓글로 요청해주세요.

간단한 뮤테이션

이번 장에서는 GraphQL API에 뮤테이션을 추가하는 방법을 배웁니다. 이 뮤테이션을 사용하면 서버에 새로운 링크를 게시할 수 있게 됩니다.

스키마 정의 확장하기

기존과 마찬가지로, GraphQL 스키마 정의에 새로운 동작을 추가하는 것부터 시작하겠습니다.

index.js 파일에서 typeDefs 상수의 내용을 다음과 같이 수정하세요.
($ .../hackernews-node/src/index.js)

const typeDefs = `
  type Query {
    info: String!
    feed: [Link!]!
  }

 type Mutation {                                    // 수정
   post(url: String!, description: String!): Link!  // 수정
 }                                                  // 수정

  type Link {
    id: ID!
    description: String!
    url: String!
 }

이 시점에서 스키마 정의를 살펴보면, 코드가 꽤 길어졌을 겁니다. 스키마를 별도의 파일로 분리하여 프로젝트를 리팩터링해봅시다!

src 디렉토리 안에 schema.graphql 파일을 새로 생성합니다.
($ .../hackernews-node/src)

touch src/schema.graphql

다음으로, 스키마 정의를 모두 schema.graphql 파일에 복사합니다.
($ .../hackernews-node/src/schema.graphql)

type Query {
  info: String!
  feed: [Link!]!
}

type Mutation {
  post(url: String!, description: String!): Link!
}

type Link {
  id: ID!
  description: String!
  url: String!
}

새로운 파일을 만들었으니, index.js를 조금 수정해주어야 합니다.

우선, typeDefs 상수를 완전히 삭제합니다. 스키마 정의가 별도의 파일에 존재하므로 더 이상 필요하지 않습니다. 다음으로, 파일의 최하단에 있는, GraphQLServer가 인스턴스로 생성되는 부분을 다음과 같이 수정하세요.
($ .../hackernews-node/src/index.js)

const server = new GraphQLServer({
  typeDefs: './src/schema.graphql',  // 수정
  resolvers,
}

GraphQLServer의 생성자에서 편리한 점은 바로 typeDefs가 String 형태로(기존에 그렇게 하였듯이) 직접 제공되어도 되고, 아니면 스키마 정의를 포함하는 별도의 파일(이것이 현재 적용한 것)을 참조해도 된다는 것입니다.

리졸버 함수 구현하기

API에 새로운 기술을 추가하는 그 다음 단계는 새로운 필드를 위한 리졸버 함수를 구현하는 것입니다.

다음으로, 아래오 같이 resolvers 함수를 수정합니다.
($ .../hackernews-node/src/index.js)

let links = [{
  id: 'link-0',
  url: 'www.howtographql.com',
  description: 'Fullstack tutorial for GraphQL'
}]
// 1
let idCount = links.length                             // 수정
const resolvers = {
  Query: {
    info: () => `This is the API of a Hackernews Clone`,
    feed: () => links,
  },
  Mutation: {                                          // 수정
    // 2
    post: (parent, args) => {                          // 수정
       const link = {                                  // 수정
        id: `link-${idCount++}`,                       // 수정
        description: args.description,                 // 수정
        url: args.url,                                 // 수정
      }                                                // 수정
      links.push(link)                                 // 수정
      return link                                      // 수정
    }                                                  // 수정
  },                                                   // 수정
}

우선, 앞서 설명한 것처럼 Link 리졸버를 완전히 제거했다는 점을 확인하시기 바랍니다. GraphQL 서버가 Link 타입에 대하여 해야할 일을 스스로 추론해낼 수 있으므로, 더 이상 필요하지 않습니다.

위에서 주석 표시한 부분들을 각각 살펴보겠습니다.

  1. 새로 생성되는 Link 항목에 대한 고유한 ID값으로 사용할 새로운 정수 변수를 추가했습니다.

  2. post 리졸버는 우선 새로운 link 객체를 생성하고, 이것을 기존의 links 리스트에 추가한 뒤 최종적으로는 새로 생성된 link를 반환합니다.

자, 리졸버 함수 전달된 2번째 인자에 대하여 논하기 딱 좋은 시간입니다. 이것이 대체 무엇일까요?

맞습니다! 이 동작으로 전달된 인자를 담고 있습니다. 지금의 경우 생성될 Linkurldescription을 말합니다. feedinfo 리졸버에서는 이와 같은 값들이 필요하지 않았습니다. 각 리졸버에 대응하는 최상위 필드들은 스키마 정의 상에서 인자를 요구하지 않았기 때문입니다.

뮤테이션 테스트하기

서버를 다시 구동하고, 새로운 API 동작들을 테스트해봅시다. 아래는 Playground에서 사용해볼 수 있는 예시 뮤테이션 코드입니다.

mutation {
  post(
    url: "www.prisma.io"
    description: "Prisma replaces traditional ORMs"
  ) {
    id
  }
}

서버 응답은 아래와 같을 겁니다.

{
  "data": {
    "post": {
      "id": "link-1"
    }
  }
}

뮤테이션을 한번 보낼 때마다 idCount의 값이 1씩 증가하고, 생성되는 링크들의 ID는 link-2, link-3, ... 와 같은 식으로 이루어질 것입니다.

뮤테이션이 잘 작동하는지 확인하려면 예전에 만들어놓은 feed 쿼리를 전송해보세요. 그러면 뮤테이션으로 생성된 새로운 게시물들이 반환될 것입니다.

ZfJQwdB.png

하지만, 서버를 중지시킨 뒤 다시 시작하면, 생성해놓은 링크들이 모두 사라지고 이들을 다시 추가해줘야 한다는 사실을 확인할 수 있을 겁니다. 방금 생성한 링크들은 메모리 상의 links 배열에 저장되기 때문이죠. 다음 장에서는 GraphQL 서버에 데이터베이스 계층을 추가하여 서버 실행 시간을 넘어 지속적으로 데이터를 저장하는 방법을 배우도록 하겠습니다.

연습 문제

GraphQL 리졸버 구현을 좀 더 연습하고 싶은 분들께 드리는 추가적인 과제가 있습니다. 지금까지 구현한 코드들을 기반으로, GraphQL API를 Link 타입에 대한 완전 CRUD 기능을 지원하도록 확장해봅시다. 즉, 아래와 같은 스키마 정의를 갖는 쿼리와 뮤테이션을 구현해봅시다.

type Query {
  # `id`값에 대응하는 단일 링크 가져오기
  link(id: ID!): Link
}

type Mutation {
  # 링크 갱신하기
  updateLink(id: ID!, url: String, description: String): Link

  # 링크 삭제하기
  deleteLink(id: ID!): Link
}