graphql-yoga 로그인 기능 tutorial
GraphQL은 페이스북이 2012년 개발하여 2015년에 공식 발표한 데이터 질의어입니다.
기존의 REST API는 서버에서 URL과 Method의 조합으로 여러 Endpoint를 설계하고, 클라이언트에서 이 정해진 Endpoint로 요청을 보냈다면
GraphQL은 클라이언트가 필요한 데이터 domain과 property만 요청하는 구조입니다. 네트워크 통신을 최적화하고 서버-클라이언트 개발자들간 소통비용을 줄일 수 있을 것으로 기대합니다.
가장 먼저 GraphQL을 이용하여 로그인기능을 만들어보려고 합니다.
1. graphql-yoga 설치
Fully-featured GraphQL Server with focus on easy setup, performance & great developer experience
graphql-yoga는 간단한 개발환경 세팅과 퍼포먼스, 개발 경험에 초점을 맞춘 GraphQL 서버입니다. express와 GraphQL server인 apollo-server를 기반으로 만들어졌습니다.
github repository에 있는 quick start를 통해 쉽고 간단하게 서버를 세팅할 수 있습니다.
프로젝트를 생성하고 graphql-yoga를 설치합니다.
$ yarn init
$ yarn add graphql-yoga
index.js파일을 생성하고 서버코드를 작성합니다.
const { GraphQLServer } = require('graphql-yoga')const typeDefs = ` type Query { hello(name: String): String! }`;const resolvers = { Query: { hello: (_, { name }) => `Hello ${name || 'World'}`, },};const server = new GraphQLServer({ typeDefs, resolvers });server.start(() => console.log('Server is running on localhost:4000'));
typeDefs, resolvers 두 property를 이용해 GraphQLServer 인스턴스를 생성해줍니다.
- typeDefs: 사용할 타입들을 정의합니다. schema property가 없으면 필수적으로 필요합니다.
- resolvers: typeDefs에 의해 지정된 필드에 대한 resolver를 정의합니다.
GraphQL의 요청은 query와 mutaion 두 종류가 존재하며, query는 데이터를 읽어올 때(Read), mutation은 데이터를 수정할 때(Create, Update, Delete)사용합니다. 먼저 서버가 동작하는지 확인하기 위해 hello라는 query를 작성했습니다.
이제 ‘yarn start’명령어를 통해 서버를 실행하면 콘솔에
‘Server is running on localhost:4000’이라는 명령어가 나타납니다. 브라우저를 통해 해당 URL로 이동하면
GraphQL전용 IDE인 GraphQL playground가 실행됩니다. 별도의 클라이언트 개발 없이 좌측에서 쿼리를 작성하면 우측에 결과가 출력해줍니다.
hello라는 쿼리에 name파라미터를 작성해 요청했더니 resolver에 구현한대로 Hello, { name }이 출력되었습니다.
2. typescript 설정
index.js파일을 타입스크립트로 마이그레이션하기 위해서는 먼저
typescript와 ts-node이 필요합니다. 해당 모듈과 개발편의를 위해 노드서버에 변경사항이 발생하면 자동으로 재시작 시켜주는 nodemon을 설치합니다. 설치가 완료한 후 typescript compiler를 초기화시켜주었습니다.
$ yarn add -D ts-node typescript nodemon
$ tsc --init
index.js파일을 index.ts로 수정하고 package.json에서 script를 다음과 같이 수정했습니다.
"start": "nodemon ./index.ts --exec ts-node"
‘yarn start’를 통해 서버를 시작합니다.
컴파일 에러가 발생한다면 tsconfig.json파일에서 ‘strict’옵션을 주석처리하거나, ts문법에 맞게 코드를 수정(타입 명시)해주면 됩니다.
3. 로그인 기능 구현하기
로그인기능을 구현하기 위해 graphql-yoga의 github repository에 있는 authentication예제를 따라서 작성했습니다. 로그인 기능을 위해서는 몇 가지 라이브러리들이 필요합니다.
express서버의 세션을 관리해주는 express-session, 패스워드를 암호화해주는 bcryptjs.
그리고 optional로 쿠키의 수명을 관리해주기 위한 ms입니다.
이제 서버는
- 로그인 여부를 확인하는 ‘isLogin’ query
- 회원가입을 하는 signup mutation
- 로그인하는 login mutation
세 가지 기능이 구현되었습니다.
isLogin은 세션에 user 데이터가 있는지 확인하여 true/false로 결과를 리턴해줍니다.
signup은 요청받은 username과 password로 data object에 새로운 user정보를 생성합니다. 같은 username이 존재하면 에러를 리턴하고, 없을 경우 password를 암호화하여 username을 key값으로 가진 user object를 생성합니다.
login은 전달받은 username으로 기존에 생성된 유저가 있는지 확인하고, 존재할 경우 password가 일치하는지 확인하여 password까지 일치한다면 세션에 user정보를 저장하고 true를 리턴합니다.
다만 현재까지는 login에 성공하더라도 isLogin에 대한 리턴값이 false로 반환될 것입니다. GraphQL playground의 credention option이 설정되지 않아 클라이언트의 session에 user정보가 담기지 않은 채로 isLogin요청을 보내기 때문인데, playground에 추가설정이 필요할 것 같습니다. 😵
playground화면 우측 상단에 있는 setting버튼을 클릭하면 설정을 변경할 수 있습니다.
“request.credentials”을 default값은 “omit”에서 “include”나 “same-origin”으로 수정합니다.
이후 다시 로그인을 시도하면
성공적으로 isLogin값이 true로 반환됩니다.
이렇게 graphql-yoga를 이용해 GraphQL 서버에 로그인기능을 구현해보았습니다. 로그인, 회원가입, 로그인 여부 확인 세 가지 요청이 모두 같은 Endpoint를 향하게 되지만 아직은 한번의 요청에 하나의 query나 mutation만 전송하고 필요로 하는 property도 하나뿐이기에 GraphQL의 이점이 실감나지 않고 있습니다. 기본적인 로그인 기능이 완료되었으니 앞으로 Domain과 로직을 추가해보도록 하겠습니다.