Prisma Client를 사용하여 서버와 데이터베이스 연결하기

이번 장에서는 Prisma API가 제공하는 인터페이스를 사용하여 우리의 GraphQL 서버와 데이터베이스를 연결합니다. 이 연결은 Prisma Client를 사용하여 구현됩니다.

Prisma Client를 사용하도록 리졸버 함수들을 갱신

이번 장의 실습을 시작하기에 앞서 코드를 조금 정리하고 리팩터링하도록 하겠습니다.

  • index.js 파일을 열고, links 배열과 idCount 변수를 제거합니다. 이제는 실제 데이터베이스에서 데이터를 불러올 것이므로 더 이상 필요하지 않습니다.

다음으로는, 방금 제거한 변수들은 아직 리졸버 함수에서 사용되고 있으므로, 리졸버 함수들의 코드를 수정해주어야 합니다. 이제 더미 데이터가 아니라, 데이터베이스로부터의 실제 데이터를 반환해주도록 만들 겁니다.

index.js 파일 안에서 resolvers 객체를 아래와 같이 수정합니다.
($ .../hackernews-node/src/index.js)

const resolvers = {
  Query: {
    info: () => `This is the API of a Hackernews Clone`,
    feed: (root, args, context, info) => { // 수정
      return context.prisma.links()        // 수정
    },                                     // 수정
  },
  Mutation: {                              // 수정
    post: (root, args, context) => {       // 수정
      return context.prisma.createLink({   // 수정
        url: args.url,                     // 수정
        description: args.description,     // 수정
      })                                   // 수정
    },                                     // 수정
  },                                       // 수정
}                                          // 수정

조금 이상하군요! 새로운 것들이 많이 생겨났으니, 무슨 일이 벌어진 건지 하나씩 살펴보도록 하겠습니다. 우선 feed 리졸버부터 보도록 하죠.

context 인자

원래 feed 리졸버는 아무런 인자로 받지 않았는데, 이제는 4개나 받습니다. 사실 세번째 인자인 context 이외에는 이 리졸버에서 딱히 필요한 것들은 아닙니다.

앞에서 리졸버 함수는 항상 4개의 인자를 받는다고 배웠던 것 기억하시나요? 이제 또 하나의 새로운 인자에 대하여 배울 차례입니다. context는 무엇일까요?

context 인자는 리졸버 체인 상의 모든 리졸버가 읽기/쓰기를 할 수 있는 자바스크립트 객체를 말합니다. 즉, 리졸버 간에 정보를 교환할 수 있도록 해주는 수단입니다. 나중에 보시겠지만, GraphQL 서버가 초기화되는 시점에 context 객체에 값을 쓰는 것도 가능합니다. 따라서, context를 사용하면 임의의 데이터나 함수를 리졸버에 전달할 수도 있습니다. 지금의 경우, prisma 클라이언트의 인스턴스를 context 객체에 추가해줄 겁니다. 자세한 것은 잠시 후에 다루도록 하죠.

참고: 본 튜토리얼은 리졸버의 4번째 인자에 대하여 다루지 않습니다. 이 주제에 대하여 더 자세히 배우려면 다음 2개 글을 읽어보시기 바랍니다.

자, 리졸버로 전달되는 인자들에 대한 기본적인 이해를 갖추었으니, 이제 이 인자들이 리졸버 함수의 코드 안에서 어떻게 사용되는지를 알아보겠습니다.

feed 리졸버의 이해

달라진 post 리졸버를 살펴보도록 하겠습니다.

($ .../hackernews-node/src/index.js)

post: (root, args, context) => {
  return context.prisma.createLink({
    url: args.url,
    description: args.description,
  })
},

feed 리졸버와 비슷하게, 단지 context 객체에 추가된 prisma 클라이언트 인스턴스의 메서드를 호출하고 있습니다.

Prisma Client API의 createLink 메서드를 실행하고, 그 반환값을 그대로 돌려줍니다. createLink의 인자로는 리졸버가 args 매개변수를 통하여 받은 데이터를 전달합니다.

요약하면, Prisma 클라이언트는 우리의 데이터베이스에 읽기/쓰기할 수 있도록 데이터 모델 상의 각 모델에 대한 CRUD API를 노출합니다. 여기서 사용되는 메서드들은 datamodel.prisma 상에서 정의된 모델 정의에 따라 자동으로 생성됩니다.

하지만 이 신비로운 prisma 클라이언트 인스턴스에, 우리가 만든 리졸버들이 제대로 접근하고 있는지 어떻게 확신할 수 있을까요?

생성된 Prisma 클라이언트를 context에 추가하기

다른 것들을 시작하기에 앞서, 자바스크립트 개발자들이 가장 사랑하는 작업부터 시작합시다. 바로 프로젝트에 새로운 의존성을 추가하는 것입니다. 😑

프로젝트 최상위 디렉토리(prisma 내부가 아닙니다)에서 아래의 명령어를 실행합니다.
($ .../hackernews-node)

yarn add prisma-client-lib

이 의존성은 Prisma 클라이언트의 자동 생성을 위하여 필요합니다.

이제, 생성된 prisma 클라이언트 인스턴스를 context에 추가하여 리졸버에서 접근할 수 있도록 해줍시다.

우선, prisma 클라이언트 인스턴스를 index.js에 불러옵니다. 파일의 가장 윗부분에 다음 import 문을 작성합니다.
($ .../hackernews-node/src/index.js)

const { prisma } = require('./generated/prisma-client')

이제 생성된 prisma 인스턴스를 GraphQLServer가 초기화될 때에 context에 추가해줍니다.

index.js 파일에서 GraphQLServer의 초기화 코드를 다음과 같이 수정합니다.
($ .../hackernews-node/src/index.js)

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

GraphQL 리졸버에서 사용되는 context 객체는 바로 이 시점에서 초기화가 이루어집니다. context 객체에 prisma 클라이언트 인스턴스를 추가하므로, 리졸버에서 context.prisma에 접근할 수 있게 됩니다.

새로운 구현 사항을 테스트하기

데이터베이스를 붙인 새로운 코드가 예상대로 잘 작동하는지 테스트해볼 시간입니다. 평소와 마찬가지로, 터미널에서 아래의 명령어를 실행하여 GraphQL 서버를 시작합니다.

($ .../hackernews-node)

node src/index.js

다음으로, http://localhost:4000으로 접속하여 GraphQL Playground를 열어봅니다. 기존과 마찬가지로 feed 쿼리와 post 뮤테이션을 전송할 수 있습니다. 하지만 이번에는 새로운 링크들이 Prisma Cloud 데모 데이터베이스에 지속적으로 보존된다는 것이 다릅니다. 따라서 서버를 다시 시작하더라도, feed 쿼리는 올바르게 링크들을 반환해줄 것입니다.

참고: 이번 실습에서는 Prisma Cloud의 데모 데이터베이스를 사용하기 떄문에, 저장된 데이터를 Prisma Cloud Console에서 열람할 수 있습니다.
ZXJ8RIY.png

Quiz

context 객체에 추가된 Prisma 인스턴스의 주요 역할로 올바른 것은?

  • 클라이언트 어플리케이션에 스키마를 노출시킨다.
  • GraphQL 동작을 Prisma API에서 JavaScript 함수로 변환한다.
  • GraphQL 동작을 어플리케이션 계층에서 JavaScript 함수로 변환한다.
  • SQL 쿼리를 생성한다.