GraphQL-API 만들기

류연찬·2023년 5월 13일
0

GraphQL

목록 보기
3/17
post-thumbnail

이번에는 Apollo Server 를 활용해 GraphQL-API 를 제공하는 서버를 개발해 보겠습니다.

Apollo Server 는 GraphQL-API를 제공하는 서버를 개발할 수 있게 도와주는 패키지로서 기존에 Node.js에서 사용하는 Express와 역할이 비슷합니다.

먼저 새로운 폴더 05-01-graphql-api-with-apollo-server-1 을 만들어주세요.

yarn init 명령어를 입력해 package.json 파일을 생성해주세요.

GraphQL-API 를 사용할 것이기 때문에 yarn add graphql 명령어를 입력해 설치해주세요.

Apollo Server는 GraphQL이 적용된 서버를 생성할 수 있는 클래스입니다.

yarn add apollo-server graphql 을 입력해 설치해주세요.

{
  "name": "05-01-graphql-api-with-apollo-server-1",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "type": "module",
  "dependencies": {
    "apollo-server": "^3.12.0",
    "graphql": "^16.6.0"
  }
}

그 후 index.js 파일을 생성해주고 설치했던 apollo-servergraphql 을 불러와줍니다.

import { ApolloServer, gql } from 'apollo-server'

mutation & query

graphql 에는 2가지 요청이 있습니다.

  • query : DB에서 데이터를 읽는 요청
  • mutation : DB를 등록, 수정, 삭제하는 요청

typeDef & resolver

apollo-servertypeDefresolver 를 인자로 받아 서버를 생성합니다.

  • typeDef : graphql 명세에서 사용될 데이터와 타입을 지정하고 template literal tag로 생성됩니다.
  • resolver : 서비스의 액션들을 함수로 지정하고 요청에 따라 데이터를 반환, 입력, 수정, 삭제합니다.
const myResolvers = {
  Query: {
    hello: () => 'world',
  }
}

myResolvers 객체 안에 Query 라는 객체를 선언하였습니다.

Query 객체 안에 world라는 문자열을 반환하는 로직을 구현하였습니다.

const myTypeDefs = gql`
	type Query {
		"A simple type for getting started!"
		hello: String
	}
`

myTypeDefs 객체 안에 type Query 객체를 선언해 반환될 데이터의 형태를 지정해 주었습니다.

const server = new ApolloServer({
  typeDefs: myTypeDefs,
  resolvers: myResolvers
});

server.listen(3000);

이제 apollo server 를 생성하고 typeDefmyTypeDefs 를, resolvermyResolvers 를 연결시켜주고 3000번 포트를 열어줍니다.

node index.js 를 입력해 apollo server 를 실행시켜줍니다.

서버가 실행되면 위와 같은 화면을 볼 수 있습니다.

Query your server를 클릭해 playground에 들어가주세요.

GraphQL-API Testing

query {
	hello
}

위와 같이 입력하고 실행하면 myResolvers 라는 객체 안에 Query 객체에 작성해 놓은 hello 함수가 실행되면서 myTypeDefs 객체 안에 type Query 객체에 지정해 놓은 데이터의 형태로 반환됩니다.

GraphQL-API 만들기 1

이번엔 본격적으로 Rest-API로 개발했던 로직을 GraphQL-API을 사용해서 개발해보겠습니다.

05-02-graphql-api-with-apollo-server-2 폴더를 만들어줍니다.

package.json05-01-graphql-api-with-apollo-server-1 에 있는 것을 복사 붙여넣기 해주세요.

04-02-rest-api-with-express-2 의 동일한 기능의 로직을 GraphQL-API 로 사용해보는 것이기 때문에 참고하시면서 개발을 진행해주시면 됩니다.

fetchBoards

const myResolvers = {
    Query: {
        fetchBoards: () => {
            // 데이터 조회하는 로직

            return '조회에 성공하였습니다.'
        }
    }
}

Rest-APIGET 메서드는 GraphQL-API에서는 모두 Query로 동작합니다.

Query 를 이용해 다음과 같이 데이터를 조회하는 기능을 구현해 주세요.

const myTypeDefs = gql`
    type Query {
        fetchBoards: String
    }
`

myTypeDefs 객체 안에 type Query 안에는 반환될 데이터의 타입을 지정해 주었습니다.

반환될 데이터의 종류가 String이기 때문에 다음과 같이 타입을 지정했습니다.

const server = new ApolloServer({
    resolvers: myResolvers,
    typeDefs: myTypeDefs
});

server.listen(3000);

이제 resolverstypeDefs 를 연결시켜주고 서버를 열어줍니다.

그 후 브라우저를 통해 접속하고 테스트 해보겠습니다.

query {
  fetchBoards
}

myResolversQuery 객체에 작성해 놓은 fetchBoards 함수가 실행되면서 type Query 에 지정해 놓은 문자열 메세지가 잘 출력됩니다.

createBoard

const myResolvers = {
    Mutation: {
        createBoard: () => {
            // 데이터 등록하는 로직

            return '등록에 성공하였습니다.'
        }
    }
}

Rest-APICRUD는 모두 GraphQL-API에서는 Mutation 으로 동작합니다.

myResolvers 안에 Mutation 을 추가해주세요.

Mutation 에는 다음과 같이 데이터를 등록하는 로직을 구현해 주세요.

const myTypeDefs = gql`
    type Mutation {
        createBoard: String
    }
`

myTypeDefs 객체 안에 tyoe Query 객체를 선언해 반환될 데이터의 형태를 지정해 주었습니다.

다시 서버를 재시작해주고 동일하게 접속해 테스트를 해보겠습니다.

mutation {
  createBoard
}

myResolvers 라는 객체 안에 Mutation 객체에 작성해 놓은 createBoard 함수가 실행되면서 type Mutation 에 지정해 놓은 문자열 메세지가 잘 출력됩니다.

GraphQL-API 만들기 2

05-03-graphql-api-with-apollo-server-3 폴더를 생성해주고 05-02-graphql-api-with-apollo-server-2 폴더에 있는 파일들을 모두 복사 후 붙여넣어주세요.

yarn install 명령어를 입력해서 package.json 에 기록되어 있는 패키지들을 설치해줍니다.

fetchBoards

이전에는 Rest-APIGET 메서드를 사용해서 데이터를 조회 후 반환해 주었습니다.

동일한 데이터를 반환하는 기능을 GraphQL-API로 변경해보도록 하겠습니다.

const myResolvers = {
    Query: {
        fetchBoards: () => {
            // 데이터 조회하는 로직

            // return '조회에 성공하였습니다.'
            return [
                { number: 1, writer: '철수', title: '제목입니다~', contents: '내용!!'},
                { number: 2, writer: '영희', title: '안녕하세요~', contents: '배고프네요'},
                { number: 3, writer: '훈이', title: '점심은 맛있게 드셨나요?', contents: '식사는 하셨나요?'},
                { number: 4, writer: '맹구', title: '안녕하세요!!!', contents: '내용입니다~'}
            ]
        }
    }
}

Query 내부에 데이터를 조회하는 로직을 작성해 주세요.

Rest-API에서는 res.send 를 이용해서 데이터를 반환했는데 GraphQL-API에서는 return 을 사용해 함수를 종료하면서 데이터를 반환합니다.

myResolvers 에 작성한 QueryfetchBoards 함수의 반환값을 한번 확인해 보세요.

const myTypeDefs = gql`
	type MyBoard {
        number: Int
        writer: String
        title: String
        contents: String
    }
    type Query {
        fetchBoards: [MyBoard]
    }
`

반환 값은 배열 안에 객체의 형태로 이루어져 있습니다.

먼저 객체의 타입을 지정해주기 위해서 type MyBoard {} 을 선언해주고 요소의 타입을 지정해주세요.

객체안의 요소들의 타입을 지정해 주었다면 MyBoard 를 배열로 감싸서 fetchBoards: [MyBoard] 과 같이 지정해 줍니다.

다시 서버를 재시작 해주고 동일하게 테스트를 해보겠습니다.

query {
  fetchBoards {
    number
    writer
    title
    contents
  }
}

myResolvers 라는 객체 안에 Mutation 객체에 작성해 놓은 createBoard 함수가 실행되면서 type Mutation 에 지정해 놓은 타입과 type MyBoard 가 지정해 놓은 요소들의 타입에 맞게 응답받았습니다.

createBoards

const myResolvers = {
    Mutation: {
        createBoard: (_, args) => {
            // 데이터 등록하는 로직

            console.log('입력값들: ', args);
            console.log('입력값들2: ', args.createBoardInput);
          
            return '등록에 성공하였습니다.'
        }
    }
}

05-02-graphql-api-with-apollo-server-2 폴더의 index.jscreateBoard 와 동일하지만 매개변수가 다르게 사용되어 있는 것을 확인할 수 있습니다.

4개의 매개변수가 있는데 다음과 같습니다.

  • parent : 부모 타입 리졸버에서 반환된 결과를 가진 객체
  • args : 쿼리 요청 시 전달된 파라미터를 가진 객체
  • context : GraphQL의 모든 리졸버가 공유하는 객체로서 로그인 인증, 데이터베이스 접근 권한 등에 사용
  • info : 명령 실행 상태 정보를 가진 객체

Rest-API 에서는 요청 데이터를 확인하기 위해 Parameter(매개변수) req를 사용했습니다.

GraphQL-API 에서는 Parameter(매개변수) args를 사용해 요청된 데이터를 확인할 수 있습니다.

만약 사용하지 않는 파라미터를 사용할때는 _ (언더바) 를 파라미터로 사용합니다.

const myTypeDefs = gql`
    input CreateBoardInput {
        writer: String
        title: String
        contents: String
    }
    type Mutation {
        createBoard(createBoardInput: CreateBoardInput): String
    }

`

이번에는 요청 데이터 타입을 지정해 보겠습니다.

다음과 같이 input 을 사용해 데이터의 타입을 지정합니다.

다시 서버를 재시작해주고 동일하게 테스트를 해보겠습니다.

mutation {
  createBoard(createBoardInput: {
    writer: "yeontan0826",
    title: "this is title",
    contents: "this is contents!!"
  })
}

input CreateBoardInput 에 지정해 놓은 요소들의 데이터 타입에 맞게 요청을 보내야 합니다.

myResolvers 라는 객체 안에 Mutation 객체에 작성해 놓은 createBoard 함숙 실행되면서 type Mutation 에 지정해 놓은 문자열 메세지가 잘 출력됩니다.

아까 리졸버에서 등록한 콘솔에도 잘 찍힌 것을 확인할 수 있습니다.

GraphQL-API 만들기 3

05-04-graphql-api-with-apollo-server-4 폴더를 생성해주고 05-03-graphql-api-with-apollo-server-3 폴더에 있는 파일들을 모두 복사 후 붙여넣어주세요.

이번에는 04-04-rest-api-with-express-3-token Rest-API로 개발했던 인증번호를 전송해주는 API를 GraphQL-API로 변경해보겠습니다.

04-04-rest-api-with-express-3-tokenphone.js 파일을 복사해서 05-04-graphql-api-with-apollo-server-4 폴더 안에 붙여넣어주세요.

import { checkValidatePhone, getToken, sendTokenToSMS } from './phone.js'

phone.js 파일에 있는 함수들을 import 해주세요.

const myResolvers = {
    Mutation: {
        createTokenOfPhone: (_, args) => {
            /// 1. 휴대폰 번호 자릿수 맞는지 확인하기
            const isValidationPhone = checkValidatePhone(args.phone);

            if(isValidationPhone === true) {
                // 2. 핸드폰 토큰 6자리 만들기
                const token = getToken(6);

                // 3. 핸드폰번호에 토큰 전송하기
                sendTokenToSMS(args.phone, token);
            }

            return '인증번호를 전송했습니다.';
        }
    }
}

Mutation 에 요청이 왔을 때 휴대전화로 인증번호를 보내주는 로직을 다음과 같이 추가헤 주세요.

const myTypeDefs = gql`
    type Mutation {
        createTokenOfPhone(phone: String!): String
    }
`

이제 요청 데이터 타입을 지정하는데 ! : Not Nullable 을 지정하여 핸드폰 번호를 필수 값과 타입을 지정하였습니다.

다시 서버를 실행시키고 테스트를 해보도록 하겠습니다.

mutation {
  createTokenOfPhone(phone: "01012345678")
}

input CreateBoardInput 필수 요소인 phone 을 입력해서 요청을 보내면 인증번호를 성공적으로 전송했다는 응답을 받게 됩니다.

만약 필수 요소인 phone 을 요청하지 않는다면 에러를 확인할 수 있습니다.

0개의 댓글