-
[GraphQL] GraphQL 시작하기 (1)프론트엔드 2020. 12. 12. 01:24728x90
이번 포스트는 freeCodeCamp의 GraphQL 코스를 진행하면서 정리한 내용으로 GrapghQL 서버를 구축해보겠습니다.
GrapghQL을 처음 접하시는 분들은 많은 도움이 되길 바랍니다.
✔ 패키지 설치
저는 몽고 디비도 함께 활용했기에 몽구스도 설치했습니다.
$ npm i -D apollo-server graphql mongoose
✔ 서버 코드 작성
ApolloServer는 GraphQL 서버 인스턴스를 생성합니다. 데이터를 정의하고 Fetch 된 데이터를 불러오는 역할을 합니다.
typeDefs에서 GraphQL 스키마를 정의하며, resolvers는 데이터를 어떻게 활용할지를 쿼리를 정의합니다.
PageSub는 뒤에서 subscription이 나올때 함께 이야기하겠습니다.
몽고 디비에 연결이 된 다음 ApolloServer를 실행합니다. 포트는 5000번으로 설정했습니다.
[index.js] const { ApolloServer, PubSub } = require('apollo-server'); const mongoose = require('mongoose'); const { MONGODB } = require('./config.js'); const resolvers = require('./graphql/resolvers/index'); const typeDefs = require('./graphql/typeDefs'); const pubsub = new PubSub(); const server = new ApolloServer({ typeDefs, resolvers, context: ({ req }) =>({ req, pubsub }) }); mongoose.connect(MONGODB, {useNewUrlParser: true, useUnifiedTopology: true}) .then(() => { console.log("MongoDB Connected"); return server.listen({port : 5000}); }) .then((res) => { console.log(`Server running at ${res.url}`); });
✔ GrapghQL 스키마 정의 (typeDefs)
gql은 자바스크립트로 GraphQL 스키마를 정의하기 위해 사용되는 템플릿 리터럴 태그입니다.
스키마를 통해 백엔드 데이터 저장소 데이터의 계층구조를 정의합니다.
- 스키마 정의 언어 (SDL : schema definition language)
GrapghQL은 사람이 쉽게 이해할 수 있는 SDL을 포함합니다. 아래와 같이 Post, Comment 등을 정의하면 됩니다.
- 스키마 타입
Scalar : 기본 프로그래밍 언어의 기본 타입들과 유사합니다. (ex: Int, Float, String, Boolean, ID)
구체적인 사용을 위해 사용자 지정 스칼라 유형도 생성 가능합니다.
Object : 아래 정의한 유형이 대부분 Object입니다. (ex: Post, Comment)
Query : 클라이언트에서 GrapghQL의 데이터를 요청하는 시작점입니다.
선언된 이름과 타입으로 정의되며, 정의된 데이터가 클라이언트로 반환됩니다.
Mutation : Query와 구조와 목적이 유사합니다. Query는 단지 읽기 작업, Mutation은 쓰기 작업의 진입점을 정의합니다.
Input : Query와 Mutation에서 사용할 수 있는 객체 타입입니다.
const { gql } = require('apollo-server'); module.exports = gql` type Post { id: ID! body: String! createdAt: String! username: String! comments: [Comment]! likes: [Like]! likeCount: Int! commentCount: Int! } type Like { id: ID! createdAt: String! username: String! } input RegisterInput{ username: String! password: String! confirmPassword: String! email: String! } type Query{ getPosts: [Post] getPost(postId: ID!): Post } type Mutation{ register(registerInput: RegisterInput) : User! login(username: String!, password: String!) : User! createPost(body: String!): Post! deletePost(postId: ID!): String! createComment(postId: String!, body: String!): Post! deleteComment(postId: ID!, commentId: ID!): Post! likePost(postId: ID!): Post! } type Subscription { newPost: Post! } `;
✔ GrapghQL Resolver 정의
Resolver는 사용자가 지정한 스키마에 대하여 데이터를 채우는 역할을 합니다.
const { AuthenticationError, UserInputError } = require('apollo-server'); const Post = require('../../models/Post'); const checkAuth = require('../../util/check-auth'); module.exports = { Query: { async getPosts() { try { const posts = await Post.find().sort({ createdAt: -1 }); return posts; } catch (err) { throw new Error(err); } } }, Mutation: { async createPost(_, { body }, context) { const user = checkAuth(context); if (body.trim() === '') { throw new Error('Post body must not be empty'); } const newPost = new Post({ body, user: user.id, username: user.username, createdAt: new Date().toISOString() }); const post = await newPost.save(); context.pubsub.publish('NEW_POST', { newPost: post }); return post; } }, Subscription: { newPost: { subscribe: (_, __, { pubsub }) => pubsub.asyncIterator('NEW_POST') } } };
✔ Subscription
실시간 애플리케이션 구현을 위해 사용되는 GraphQL의 operation입니다.
같은 opertaion인 query와 mutation이 서버/클라이언트 모델로 구성된 것과 달리 subscription은 발행/구독 모델 구성입니다.
서버/클라이언트 모델에서 시스템에 이벤트가 동시다발적으로 발생하는 경우,
-> 클라이언트에서 데이터를 계속적으로 호출한다 하더라도 실시간성 보장엔 어려움이 있습니다
발행/구독 모델에서 시스템에 이벤트가 동시다발적으로 발생하는 경우,
-> 위의 모델이 HTTP 프로토콜을 사용하는 것과 달리 해당 모델은 웹소켓 프로토콜을 사용합니다.
웹소켓 프로토콜을 통해 클라이언트와 서버를 연결한 채 유지하며, 서버의 이벤트를 실시간으로 수신받을 수 있습니다.
위에서 설명 안 하고 넘어갔던 PubSub이 Apollo Server의 자체 발행/구독 엔진입니다.
Subscription 구현
-> PubSub 객체를 임포트 및 typeDefs에 Subscription 타입을 정의합니다.
마지막으로 앞서 정의한 Subscription의 동작을 Resolver에서 추가합니다.
pubsub 객체의 asyncIterator()를 호출하고 'NEW_POST'라는 이벤트를 등록하면, 해당 이벤트가 발생할 때마다 동작하게 됩니다.
✔ 서버 구동
index.js 파일에 5000번 포트에서 서버가 구동되도록 해두었으니 실행시키면 됩니다.
5000번 포트에 접속하면 아래와 같이 웹 기반 툴을 확일할 수 있습니다. 직접 쿼리를 날려 잘 동작하는지 확인해보시면 됩니다.
$ node index.js Listening at http://localhost:5000/
✔ 마무리
GraphQL를 시작하면서 먼저 간단하게나마 ApolloServer를 구현하고 실행시켜 보았습니다.
아직 다루지 못한 내용들이 많은데 추후에 계속 포스트를 업데이트하도록 하겠습니다.
'프론트엔드' 카테고리의 다른 글
DoIt 리액트 프로그래밍 정석 (3장) (0) 2020.12.12 [GraphQL] GraphQL 시작하기 (2) (0) 2020.12.12 [ReactJS] DoIt 리액트 프로그래밍 정석 (1, 2장) (0) 2020.12.11 [ReactJS] DoIt 리액트 프로그래밍 정석 (6장) (0) 2020.11.09 [ReactJS] 컴포넌트 생명주기 (0) 2020.11.08