Halo World

[GraphQL] Apollo-server 셋팅 본문

개발 지식/DEVELOPMENT

[GraphQL] Apollo-server 셋팅

_Yeony 2022. 2. 8. 00:34

본 포스팅은 Inflearn 얄코님 강의를 수강하며 복습용으로 작성하였습니다.

https://www.inflearn.com/course/%EC%96%84%ED%8C%8D%ED%95%9C-graphql-apollo/dashboard

 

[무료] 얄팍한 GraphQL과 Apollo - 인프런 | 강의

⚡ 짧고 굵은 전체 90분 강좌! 사이트의 코드들을 복붙하며 빠르게 GraphQL을 배우고 아폴로 사용법을 익히세요., - 강의 소개 | 인프런...

www.inflearn.com

 

 

apollo-server 셋팅


1. 프로젝트 생성 및 실행 테스트

npm init
npm start // package.json에서 "start" : "nodemon index.js"로 초기 셋팅

 

2. Mock DB 모듈 삽입

mock DB는 https://gitlab.com/yalco/yalco-inflearn-graphql-apollo 의 2-1에 있는 폴더로 이용. 해당 폴더를 프로젝트 내부로 이동

//필요한 모듈 설치
npm i convert-csv-to-json
npm start

 

3. Apollo 서버 설치

npm i graphql apollo-server //아폴로 서버 모듈 설치
const database = require('./database')
const { ApolloServer, gql } = require('apollo-server')

//주고받을 데이터 형식 정의
const typeDefs = gql`
  type Query {
    teams: [Team]
  }
  type Team {
    id: Int
    manager: String
    office: String
    extension_number: String
    mascot: String
    cleaning_duty: String
    project: String
  }
`

//각 요청을 받았을 때 어떤 액션을 할 것인지 정의
const resolvers = {
  Query: {
    teams: () => database.teams
  }
}

//typeDefs와 resolvers를 인자로 받는 apollo server 생성
const server = new ApolloServer({ typeDefs, resolvers })
server.listen().then(({ url }) => {
console.log(`🚀  Server ready at ${url}`)
})
  • typeDefs
    • GraphQL 명세에서 사용될 데이터, 요청의 타입 지정
    • gql(template literal tag)로 생성됨
  • resolver
    • 서비스의 액션들을 함수로 지정
    • 요청에 따라 데이터를 반환/입력/수정/삭제함
//서버 재실행
npm start
  • 실행된 http://localhost:4000 에서 로컬 서버에 쿼리 및 테스트 가능
//조회 쿼리 테스트
query {
  teams {
    id
    manager
    office
    extension_number
    mascot
    cleaning_duty
    project
  }
}

 

 

Query 구현하기


1. 모든 team 리스트 받아오기

  • typeDefs에 Query 루트타입 및 teams 명령어 정의
  • 쿼리 명령문 마다 반환될 데이터 형태를 지정

 

    type Query {
    	//teams라는 명령어는 team 리스트를 반환함
        teams: [Team]
    }
  • tepyDefs에 데이터 형태 정의
    //Teams 명령어에 사용될 team이라는 데이터의 형식 정의
    type Team {
        id: Int
        manager: String
        office: String
        extension_number: String
        mascot: String
        cleaning_duty: String
        project: String
    }
  • Resolver에 해당 함수 정의
const resolvers = {
  Query: {
  //teams 명령어는 database에 있는 teams를 반환함
  //실제 프로젝트에서는 DB를 조회하는 쿼리(sql, nosql 명령어) 사용
    teams: () => database.teams
  }
}
  • 로컬 서버 playground에서 쿼리 테스트
query {
  teams{
    id,
    manager,
    office,
    extension_number,
    mascot,
    cleaning_duty,
    project,
  }
}

 

2. 특정 team만 받아오는 경우

  • args로 주어진 id에 해당하는 team만 필터링하여 반환
Query: {
    //...
    team: (parent, args, context, info) => database.teams
        .filter((team) => {
            return team.id === args.id
        })[0],
}
  • id를 인자로 받아 하나의 Team 데이터 반환
type Query {
    ...
    team(id: Int): Team
}
  • 쿼리 테스트 
query {
//team들 중 id가 1인 team만 반환
team(id: 1) {
    id
    manager
    office
    extension_number
    mascot
    cleaning_duty
    project
}
}

 

아래 자료 참고하여 equipmets, supplies 등 다양한 추가 쿼리 실습

https://www.yalco.kr/@graphql-apollo/2-2/

 

 

Mutation 구현하기


Query와 Mutation은 개발자들간의 합의된 명세

- 정보들을 받아올때는 쿼리

- 해당 정보를 추가, 수정, 삭제 할때는 Mutation

 

1. Equipment 데이터 삭제하기

  • typeDefs에 Mutation 정의
type Mutation {
	//Equipment를 삭제하고, 삭제된 Equipment를 반환
    deleteEquipment(id: String): Equipment
  }
  • resolve에 함수 정의
Mutation: {
      deleteEquipment: (parent, args, context, info) => {
      
      	  //실제로는 DB에 필요한 쿼리문 (sql이나 몽고DB 명령어처럼 실제 DB를 위해 필요한 코드
          //해당 실습에서는 mock DB를 활용하는 메소드로 대체
          const deleted = database.equipments
              .filter((equipment) => {
                  return equipment.id === args.id
              })[0]
          database.equipments = database.equipments
              .filter((equipment) => {
                  return equipment.id !== args.id
              })
          return deleted
      }
}
  • 로컬 서버 playground에서 쿼리 테스트
mutation {
  deleteEquipment(id: "notebook") {
    id
    used_by
    count
    new_or_used
  }
}

    * 해당 항목이 삭제된 것 반환값과 함께 확인 가능

 

2. Equipment 데이터 추가하기

  • typeDefs에 insert Mutation 정의
type Mutation {
	//insert한 후 해당 Equitment 반환
    insertEquipment(
        id: String,
        used_by: String,
        count: Int,
        new_or_used: String
    ): Equipment
    ...
}
  • resolve에 함수 정의
Mutation: {
	//여기서 args는 Equitment와 동일한 데이터 구조를 갖고 있음
    //해당 데이터를 db에 바로 push 
    insertEquipment: (parent, args, context, info) => {
        database.equipments.push(args)
        return args
    },
    //...
}
  • 로컬 서버 playground에서 쿼리 테스트
mutation {
  insertEquipment (
    id: "laptop",
    used_by: "developer",
    count: 17,
    new_or_used: "new"
  ) {
    id
    used_by
    count
    new_or_used
  }
}
  • insert 한 결과 확인 가능 (query시 해당 데이터도 반환되는 것 볼 수 있음)

 

3. Equipment 데이터 수정하기

  • typeDefs에 update Mutation 정의
type Mutation {
    editEquipment(
        id: String,
        used_by: String,
        count: Int,
        new_or_used: String
    ): Equipment
    ...
}
  • resolve에 함수 정의
Mutation: {
    // ...
    editEquipment: (parent, args, context, info) => {
        return database.equipments.filter((equipment) => {
            return equipment.id === args.id
        }).map((equipment) => {
            Object.assign(equipment, args)
            return equipment
        })[0]
    },
    // ...
}
  • 로컬 서버 playground에서 쿼리 테스트
mutation {
  editEquipment (
    id: "pen tablet",
    new_or_used: "new",
    count: 30,
    used_by: "designer"
  ) {
    id
    new_or_used
    count
    used_by
  }
}