프로젝트 개요

4주 프로젝트를 진행 했을 때
서버에서 가장 메인이 되었던 기술은 GraphQL입니다.

나머지 프로젝트 개요를 작성한다.(노션 링크까지 같이)

GraphQL을 선택한 이유

코드스테이츠에서 이머시브 코스를 수강하는 중에는 REST API를 학습했었습니다.
그러나 우연하게 GraphQL에 대해서 알 수 있는 기회가 있었고 궁금증을 가지게 되었습니다.

REST API와 GraphQL에 차이는 무엇일까? 를 직접 두 가지 방식을 사용하여
차이점을 몸소 느껴보고싶었습니다.

그것이 2주 프로젝트에서는 REST API 방식 4주 프로젝트에서는 GraphQL 방식을 사용한 이유입니다.

GraphQL이란?

  1. GraphQL(Graph Query Language)

    REST API 와 같이 서버로부터 데이터를 응답으로 받기 위하여 어떤 방식으로 요청할지에 대해서 정의한 문법입니다.
    페이스북에서 만들어졌습니다.

  2. GraphQL의 탄생 배경

    • FaceBook의 서비스 구동 환경은 다양합니다.
      Android, Ios, Web 환경이 있습니다.

    • 다양한 구동 환경의 문제점.

      • 각 구동 환경마다 필요한 데이터의 형태가 같지 않다는게 가장 큰 문제 였습니다.
      • 우선 응답받을 데이터의 형태가 같지 않다면 요청에 대한 endpoint가 그만큼 늘어나야 하기 때문입니다.
    • 그래서 FaceBook은 모바일 환경과 웹 환경에서의 API들을 일일히 구현 하는것이 매우 힘들었다고 합니다.

    • FaceBook이 내놓은 해결책은 간단했습니다.

      • 단순하게 하나의 응답만을 반환하는 다수의 EndPoint가 아니라
      • 동적으로 변하는 응답을 반환하는 단 하나의 EndPoint!
  3. GraphQL이 REST API 보다 나은 확실한 이유 2가지!

    1. OverFetching!

      • OverFetching이란 불필요한 데이터까지 응답으로 받아오는 REST API의 단점중 하나입니다.
      • 예를 들어 특정 유저의 userName이 필요하다면
      • /users/1로 request 합니다.
      • 그러면 Server는 작성해놓은 EndPoint에 의해
          {
            userName: "jake",
            email: "jake@naver.com",
            profileImage: "url"
          }
      • userName만 필요한 상황이지만 불필요한 데이터인 email과 profileImage까지 응답으로 받게 됩니다.
      • REST API에서 이 OverFetching 문제를 해결하기엔 제생각으로는 userName만 응답으로 반환하는 API를 따로 구현을 해야된다고 생각이 듭니다.
      • 하지만 그 방법은 별로 실현시키고 싶지 않은 방법이란 생각이 듭니다.
      • OverFetching 문제는 GraphQL에서 해결이 가능합니다.(다음 단락에서 설명하겠습니다.)
    2. UnderFetching!

      • UnderFetching이란 여러 종류의 데이터를 받기 위해 여러번의 요청을 보내는 문제를 말합니다.
      • 예를 들어 화면을 구성하는 요소 중에 유저의 이름, 게시글 목록, 현재 접속한 유저들의 목록을 띄우고 싶다면
      • /boards, /users/1, /users 로 request를 합니다.
      • 이 request들은 한 번에 모든 요청을 보낼 수 없습니다.
      • 결국에는 한 화면을 구성하기 위해서 총 3번의 요청을 보내는 문제가 생깁니다.
      • 이 문제 또한 GraphQL에서 해결할 수 있습니다.(다음 단락에서 설명하겠습니다.)
  4. GraphQL의 중요한 3가지

    1. Query

      • Query는 Server로 보내는 요청입니다.
      • 예시 코드
              // 서버로 쿼리문의 형태로 요청을 보냅니다.
              query {
                convenienceStore {
                  apple,
                  pork
                }
              }
        • Query 요청은 다른 사람에게 부탁을 하는것 이라고 생각합니다.
          • convenienceStore에서 사과와 돼지고기를 사와달라고 생각하면 됩니다.
      • 그리고 그 부탁(요청)은 한 번에 여러가지의 일도 맡길 수 있습니다.

           query {
             convenienceStore {
               apple,
               pork
             },
             tailorShop { // 한 번의 요청에 다른 종류의 데이터를 받아 올 수 있습니다.
               shoes
             }
           }
        • 부탁은 한 번에 여러가지 일도 맡길 수 있습니다.
          • convenienceStore와 tailorShop에서 각각 다른 데이터를 가져오고 있습니다.
          • REST API의 UnderFetching 문제를 해결 할 수 있습니다.
      • 부탁(요청)의 내용 또한 언제든 달라질 수 있습니다.

           query {
               convenienceStore { // 받아올 데이터의 형태가 달라졌습니다.
                   snack  
               },
               tailorShop {
                   shoes
               }
           }
        • 같은 EndPorint로 요청을 보내더라도 받아올 데이터의 형태가 달라 질 수 있습니다.
        • REST API의 OverFetching 문제를 해결할 수 있습니다.
    2. Schema

      • GraphQL의 Schema는 Database의 Schema와 유사합니다.
          type Query {
            convenienceStore: { 
              pork: String!
              apple: String!
              snack: String!
            }
            tailorShop: {
              suit: String!
              shoes: String!
            }
          }
      • 요청을 받았을 때 어떤 속성을 어떤 타입으로 반환할지에 대한 정의입니다.
        • convenienceStore와 tailorShop에서 판매하는 물품 목록이라고 생각하면 됩니다.
    3. Resolver

      • Resolver는 실제로 데이터를 반환하는 부분입니다.
          export default{
            Query: {
               convenienceStore: (root, args, context, info) => {
                     return {
                       pork: "Pork!",
                       apple: "Apple!",
                       snack: "Snack!"
                  }
              },
              tailorShop: (root, args, context, info) => {
                return {
                  shoes: "Shoes!",
                  suit: "Suit!"
                }
              }
            }
         }
        • Resolver가 바로 REST API의 Controller라고 생각하면 될 것 같습니다.
        • Resolver로 원하는 데이터만을 Query로 작성하여 요청을 보내면 Resolver에서 데이터를 응답으로 반환합니다.
        • 이 부분은 실제 가게에서 판매하는 물품이라고 생각하면 됩니다.

내가 느낀 GraphQL?

GraphQL에 대해서 공부를 하고 나서 처음으로 느꼈던 점은 거대한 쇼핑몰 같다는 생각이 들었습니다.
한 번 요청을 보낼 때마다 쇼핑몰에 입장하여 원하거나 혹은 필요한 물건들만 구매하여 집으로 돌아간다는 느낌을 받았기 떄문입니다.

REST API와는 확연히 다른 느낌입니다.
REST API에서 느꼇던건 멀리 멀리 동떨어져 있는 가게들을 한 번의 요청이 오면 딱 하나의 가게 밖에 가지 못한다고 느꼈기 때문입니다.

내가 느낀 GraphQL의 문제점?

프로젝트를 진행하면서 큰 문제에 봉착하게 됩니다.
바로 카카오 소셜 로그인이 문제였습니다.

카카오 소셜 로그인의 흐름
1. 클라이언트에서 서버로 요청을 보낸다.
2. 서버에서 카카오로 유저 인증을 위한 요청을 보낸다.
3. 카카오에서 유저 인증을 완료한다.
4. 다시 서버로 요청을 리다이렉트한다.
5. 모든 요청이 완료 되면 클라이언트로 응답을 보내준다.

위의 흐름 중 카카오에서 다시 서버로 요청을 보내는 부분에서 문제가 생겼습니다.
GraphQL의 서버는 Endpoint가 단 하나!
그러나 카카오에서 서버로 리다이렉트를 해줄 url을 설정해야 했습니다.

이 부분에서 팀원들과 EndPoint가 하나이기 때문에 발생한 문제를 어떻게 해결해야 하나 고민했습니다.

문제점의 해결방법

놀랍게도 이 문제는 간단하게 해결되었습니다.

바로 REST API를 같이 사용하면 해결될 문제였습니다.

저는 GraphQL 서버에서는 무조건 GraphQL 방식을 고수해야만 하는 줄 알았지만
딱히 그런 것도 아니었습니다.
REST API를 사용해야 될 부분에서는 그냥 REST API 방식을 이용하면 됐습니다.

하지만 조심해야될 부분이 있는데
기능 하나를 구현할 때에 GraphQL 방식과 REST API 방식을 사용하는 건 그다지 좋은 방법이 아니기 떄문에
독립적인 기능일 때에만 두 가지 방식을 혼용해서 써야합니다.

마무리

GraphQL은 REST API의 상위 호환이 아니며 REST API를 대체할 수 있는 하나의 스펙이라고 생각합니다.
두 가지 방식의 장단점을 잘 파악하여 GraphQL만을 사용한 서버 혹은 REST API만을 사용한 서버 그것도 아니라면 두 가지 모두 혼용한 서버를 구축할지 설계를 해야할 것 입니다.