티스토리 뷰

요즘 GraphQL에 대한 이야기가 많이 들려와서 나도 간단한 어플을 한번 만들어보려고 공부를 시작해 보았다. 우선 간단 한 예제를 한 번 만들어 보려고 한다.


1. Project 생성 및 Dependencies 설치

$ mkdir graphql-test //프로젝트 생성
$ cd graphql-test // 해당 폴더로 경로 이동
$ npm init -y //package.json 생성
$ npm install //node_modules 설치
$ npm install --save express express-graphql graphql 
$ npm install --save axios json-server nodemon

 

2. express 서버에 graphQL 미들웨어 사용 설정

 

파일 이름: server.js

const express = require('express');
const expressGraphQL = require('express-graphql');

const schema = require('./schema/schema')


const app = express();

//GraphQL설정
app.use('/graphql', expressGraphQL({
    schema,
    graphiql: true
}));

app.listen(4000, ()=> {
    console.log('Listening');
});

 

3. 스키마 생성

스키마란 GraphQL에서 어떤 데이터를 어떻게 다룰 것인지, 또한 데이터들끼리 서로 어떻게 연관되어있는지 범위를 정하는 것이다.

참고로 샘플 예제에서는 2개의 테이블을 사용하려고 한다. 첫 번째는 user테이블로 유저 정보를 저장한다. 나머지 하나는 company테이블로 유저들이 다니고 있는 회사의 메타 정보를 저장하는 테이블이다.

 


참고로 데이터베이스 대신 json-server를 사용하려고 한다. json-server에 대해서는 아래의 링크를 통해 자세히 확인할 수 있다.

 

typicode/json-server

Get a full fake REST API with zero coding in less than 30 seconds (seriously) - typicode/json-server

github.com

[db.json]

{
  "users": [
    {
      "id": "23",
      "firstName": "Bill",
      "age": 20,
      "companyId": "1"
    },
    {
      "id": "25",
      "firstName": "Sam",
      "age": 24,
      "companyId": "2"
    },
    {
      "id": "10",
      "firstName": "Min",
      "age": 20,
      "companyId": "2"
    },
    {
      "firstName": "Bam",
      "age": 30,
      "id": "3eCgTZi",
      "companyId": "3"
    }
  ],
  "companies": [
    {
      "id": "1",
      "name": "Apple",
      "description": "iphone"
    },
    {
      "id": "2",
      "name": "Google",
      "description": "search"
    },
    {
      "id": "3",
      "name": "Amazon",
      "description": "shopping"
    }
  ]
}

이제 스키마를 생성해보자. 

 

파일이름: /schema/schema.js

(참고: 스키마를 작성하는데 필요한 dependencies)

const graphql = require('graphql');
const axios = require('axios');
const {
    GraphQLObjectType,
    GraphQLString,
    GraphQLInt,
    GraphQLSchema,
    GraphQLList,
    GraphQLNonNull
} = graphql;

 

(1) 데이터 Type생성

먼저 Type들을 생성해 줄 것이다. Type은 테이블에 매핑되는 Object라고 생각하면 된다.

 

[CompanyType]

 

먼저 CompanyType을 생성해주자. 해당 타입을 대표하는 이름(name)을 설정하고 해당 타입의 Property들을 fields란에 입력해 주자. 참고로 users같은 경우 각각 company의 id를 companyId로 가지고 있는 유저들의 정보를 가져오는 것이다. 실제로 데이터베이스와 소통할 때는 resolve를 사용하는데 resolve에는 2가지 인자 값이 존재한다.

- parentValue: 부모 데이터 값으로 CompanyType 데이터의 값이 들어온다.

- args: 유저가 데이터를 가져오기 위해 입력하는 값들이 들어온다.

const CompanyType = new GraphQLObjectType({
    name: 'Company',
    fields: ()=>( {
        id: { type: GraphQLString},
        name: {type : GraphQLString},
        description: { type: GraphQLString},
        users: {
            type: new GraphQLList(UserType),
            resolve(parentValue, args) {
                return axios.get(`http://localhost:3000/companies/${parentValue.id}/users`)
                    .then(res => res.data)
            }
        }
    })
})

 

[UserType]

const UserType = new GraphQLObjectType({
   name: 'User',
   fields: () => ({
       id: { type: GraphQLString},
       firstName: { type: GraphQLString },
       age: { type: GraphQLInt},
       company: {
           type: CompanyType,
           resolve(parentValue, args) {
               return axios.get(`http://localhost:3000/companies/${parentValue.companyId}`)
                   .then(resp => resp.data);
           }
       }
   })
});

 

(2) Root Query생성

해당 타입들을 통해 쿼리를 Select 해 오려면 RootQuery가 필요하다. 필요한 쿼리들을 fields안에 입력해주자.

 

[Root Query]

const RootQuery = new GraphQLObjectType({
    name: 'RootQueryType',
    fields: {
        user: {
            type: UserType, //return type
            args: { id: { type: GraphQLString}}, //give me id
            resolve(parentValue, args) { // go into Actual DB
                return axios.get(`http://localhost:3000/users/${args.id}`)
                    .then(resp => resp.data);
            }
        },
        company: {
            type: CompanyType,
            args: { id: { type: GraphQLString}},
            resolve(parentValue, args) {
                return axios.get(`http://localhost:3000/companies/${args.id}`)
                    .then(resp => resp.data);
            }
        }
    }
});

user: user 정보를 가져오는 쿼리

company: company정보를 가져오는 쿼리

type: 해당 쿼리를 실행 시 리턴되는 데이터 타입

args: 쿼리를 작성하는데 필요한 값들을 설정

resolve: 실제로 DB와 소통하여 데이터를 가져오는 로직을 담고 있는 함수.

 

(3) Mutation설정 

데이터를 수정, 생성, 삭제 할 경우 RootQuery가 아닌 mutation을 사용한다.

 

[mutation]

const mutation  = new GraphQLObjectType({
    name: 'Mutation',
    fields: {
        addUser: {
            type: UserType,
            args: {
                firstName: { type: new GraphQLNonNull(GraphQLString) },
                age: { type: new GraphQLNonNull(GraphQLInt)},
                companyId: { type: GraphQLString }
            },
            resolve(parentValue, { firstName, age}){
                return axios.post('http://localhost:3000/users', { firstName, age})
                    .then(resp => resp.data);
            }
        },
        deleteUser: {
            type: UserType,
            args: {
                id: {type: new GraphQLNonNull(GraphQLString)}
            },
            resolve(parentValue, {id}){
                return axios.delete(`http://localhost:3000/users/${id}`)
                    .then(resp=> {
                        console.log(resp.data);
                        return resp.data;
                    });
            }
        },
        updateUser: {
            type: UserType,
            args: {
                id: {type: new GraphQLNonNull(GraphQLString)},
                firstName: {type: GraphQLString},
                age: {type: GraphQLInt}
            },
            resolve(parentValue, {id, firstName, age}){
                return axios.patch(`http://localhost:3000/users/${id}`, {firstName, age })
                    .then(resp=> resp.data);
            }
        }
    }
});

 

(4) Export 하기

module.exports = new GraphQLSchema({
    query: RootQuery,
    mutation
});

 

4. GraphiQL를 실행시켜보자

 

먼저 다음과 같이 명령문을 작성하여 서버를 실행시킨다.

$ node server.js

이후 localhost:4000/graphql로 이동하면 다음과 같은 화면이 보인다.

 

(1) Select Query

 

[유저]

 

[유저+회사 정보]

 

[회사 정보]

 

[특정 회사에 다니는 유저 정보]

*Fragment사용 방법

(2) Mutation

[유저 생성]

[유저 수정]

[유저 삭제]


 

심심해서 강의를 따라 해 보면서 간단한 예제를 만들어 봤는데 생각보다 되게 재미있었다. weekly 말고 생각 중인 Toy Project가 있는데 그건 GraphQL로 만들어 봐야겠다 🤔

댓글