안녕하세요. devport 입니다. 이번 포스팅에서는 NodeJS로 간단한 Apollo 서버를 구축하고 GraphQL Playground로 Query 및 Mutation이 어떻게 동작되는지 자세하게 훑어보려고합니다. 예제는 처음 공식 홈페이지의 서버 구축 예제로 시작하도록 하겠습니다.
Npm 설치
npm install --save apollo-server-express express
Apollo 라이브러리를 웹서버에 올려 사용할 수있는 환경을 구축하기 위해서 관련 라이브러리를 프로젝트에 설치합니다.
server.js
프로젝트 하위에 server.js파일을 생성하여 아래 코드를 삽입하여 줍니다.
const express = require('express');
const { ApolloServer, gql } = require('apollo-server');
const typeDefs = gql`
type Query {
hello: String
}
`;
const resolvers = {
Query: {
hello: () => 'Hello world!',
},
};
const server = new ApolloServer({ typeDefs, resolvers });
const app = express();
server.applyMiddleware({ app });
app.listen({port: 4000}, () => {
console.log('Now browse to http://localhost:4000' + server.graphqlPath)
})
express 모듈은 웹서버를 모듈이며 apollo-server모듈은 /graphql 경로의 진입부를 마운트할 수 있도록 하였습니다.
node server.js
위 커맨드를 쉘에서 실행하게 되면 Express 웹서버가 실행됩니다.
브라우저에서 http://localhost:4000/graphql 경로로 접근하게 되면 아래와 같은 Graphql Playground 화면을 볼 수 있게됩니다.
이 화면에서 Docs에서는 Query, Mutation에 목록을 확인할 수 있으며 Schema에서는 전체적인 구조를 확인할 수 있습니다. 또한 Query(검색) 및 Mutation(추가,수정,삭제)을 Playground에 작성하고 실행시킨다면 결과값을 바로 확인할 수 있다는 이점을 가지고 있습니다.
Query 및 Mutation을 해보자
이제 간단하게 Query 및 Mutation을 해보기 위해서 스키마를 재정의 해보도록 하겠습니다.
const typeDef = gql`
type Author {
id: ID
name: String
books: [Book]
}
type Book {
id: ID
title: String
author: String
}
type Query {
allAuthor: [Author]
allBook: [Book]
}
type Mutation {
createAuthor(name: String!): Author
createBook(title: String!, author: String!): Book
deleteAuthor(id: ID!): Author
deleteBook(id: ID!): Book
}
`
스키마에 Author, Book type을 선언 하였습니다.
Author 타입은 저자의 객체를 담을 수 있는 구조로써 이름과 책들의 정보를 가져올 수 있는 구조입니다.
Book 타입은 책의 객체를 담을 수 있는 구조로써 책제목, 저자의 이름 정보를 가져올 수 있는 구조입니다.
Query에서
allAuthor는 저자들의 목록을 반환 받을 수 있습니다.
allBook은 책들의 목록을 반환 받을 수 있습니다.
Mutation에서
createAuthor는 저자를 추가하는 변이로써 저자의 이름을 필수적으로 인자를 삽입해야 합니다.
createBook은 책을 추가하는 변이로써 책의 이름과 저자이름을 필수적으로 인자를 삽입해야 합니다.
deleteAuthor는 특정 저자를 제거 할 수 있으며 대상의 id를 필수적으로 삽입해야 합니다.
deleteBook은 특정 책을 제거할 수 있으며 대상의 id를 필수적으로 삽입해야 합니다.
위 스키마에서 저자와 책에 대하여 선언을 하였으며 검색, 추가, 삭제에 관련된 Query 및 Mutation들을 선언하였습니다. 선언된 내용들에 대해서 아래와 같이 구현을 하였습니다.
let authorList = []; // 저자의 목록
let bookList = []; // 책의 목록
let authorCnt = 0, bookCnt = 0; // 저자,책의 id 순번
let resolvers = {
Query: {
// 저자 목록 검색
allAuthor: () => authorList,
// 책 목록 검색
allBook: () => bookList,
findAuthor: ({id}) => authorList.find((author) => {author.id == id}),
findBook: ({id}) => bookList.find((book) => {book.id == id})
},
Mutation: {
// 저자 추가
createAuthor (parent, {name}) {
const author = {id: authorCnt++, name}
authorList.push(author);
return author;
},
// 책 추가
createBook (parent, {title, author}) {
const book = {id: bookCnt++, title, author};
bookList.push(book);
return book;
},
// 저자 삭제
deleteAuthor (parent, {id}) {
const idx = authorList.findIndex((author) => author.id == id);
let author = {};
if (idx>=0) {
author = authorList[idx];
authorList.splice(idx, 1);
}
return author;
},
// 책 삭제
deleteBook (parent, {id}) {
const idx = bookList.findIndex((book) => book.id == id);
let book = {};
if (idx>=0) {
book = bookList[idx];
bookList.splice(idx, 1);
}
return book;
}
},
// 연쇄 리졸버
Author: {
// 저자의 books 정보를 검색
books (parent) {
const list = []
bookList.forEach((book) => {
if (book.author === parent.name) list.push(book);
})
return list;
}
}
};
authorList(저자의 목록), bookList(책의 목록)에 대한 검색, 추가, 삭제를 구현한 리졸버입니다.
위 예제에서는 간단히 배열을 사용하고 있지만 구현된 위치에 DB를 사용하고 CRUD 로직만 변경해준다면 웹서버 + 데이터베이스로 GraphQL을 서비스할 수 있는 구조로 탈바꿈하게 됩니다.
GraphQL Playground에서 간단하게 저자 및 책을 추가하고 검색을 해보도록 하겠습니다.
"모든 저자 검색"을 하였을때에 books는 Author.books 리졸버를 호출하여 저자명과 일치하는 책을 반환하게 되며 의존 정보를 쉽게 검색할 수 있는 것을 알 수 있습니다. 이러한 기법을 연쇄 리졸버라고 하여 연관데이터를 쉽게 구할 수 있다는 것을 알 수 있었습니다.
'개발바닥 > GraphQL' 카테고리의 다른 글
[개발] GraphQL - Apollo Link 제어 (0) | 2021.11.10 |
---|---|
[개발] GraphQL - Apollo Client Cache (0) | 2021.11.10 |
[개발] GraphQL - Vue + Apollo + GraphQL (0) | 2021.11.10 |
[개발] GraphQL - Schema & Type (0) | 2021.11.10 |
[개발] GraphQL을 알아보자. (0) | 2021.11.10 |