GraphQL을 사용하며 느낀 장단점

Moondy·2022년 8월 20일
3

❓GraphQL이란?

  • 페이스북에서 만든 쿼리 언어
  • SQL이 데이터 베이스 시스템에 저장된 데이터를 효율적으로 가져오는 쿼리언어라면
    GraphQL(이하 gql)은 웹 클라이언트가 데이터를 서버로부터 효율적으로 가져오는 쿼리
    아직 early-stage에 있는 기술이긴 하지만, 인기가 점점 높아지는 중

    그림 출처: https://2019.stateofjs.com/ko/data-layer/graphql/

❗️GraphQL 특징

  • 하나의 EndPoint에 여러 API 요청 가능
    • hero, villain 두가지 API를 한번에 요청 가능
  • 필요한 정보만 요청할 수 있음
    • villain 객체에 name, movie 등 여러 Field가 있는데, 그 중 필요한 name만 요청할 수 있다
  • Depth있어도 해당 객체의 필요한 필드만 요청 가능. 반복문으로 DTO 파싱 및 필터링 없음
    • hero.friends의 field 중에서 필요한 name만 요청할 수 있다.
  • Overfetching 방지
    • 원하는 데이터 이상의 정보를 요청받는것. data 정제에 리소스 낭비
  • Underfetching 방지
    • 원하는 data의 정보를 요청받기 위해 여러번 요청을 보내는것.
  • REST API에서는 프론트엔드 개발자는 백앤드 개발자가 작성하여 전달하는 API의 request / response의 형식에 의존하게 된다. 그러나, GraphQL을 사용한 방식에 서는 이러한 의존도가 많이 사라진다. 다만 여전히 데이터 schema에 대한 협업 의존성은 존재한다.

Request

  • query: REST API에서 GET과 비슷한 개념
  • Request 부분(hero, villain처럼 API 이름 등)과 Response에서 요청할 데이터(name, friends와 같은 필드명)을 모두 명시한다
query{
  hero {
    name
    friends {
      name
    }
  }
  villain {
    name
  }
}

Response

  • request에서 요청한 데이터만 Response에 담아서 리턴됨
{
  "data": {
    "hero": {
      "name": "R2-D2",
      "friends": [
        {
          "name": "Luke Skywalker"
        },
        {
          "name": "Han Solo"
        },
        {
          "name": "Leia Organa"
        }
      ]
    }
    "hero": {
      "name": "Thanos"
    }
  }
}

응답 객체

  • Backend, Frontend 모두 스키마를 가지고 있어야하고, 그 스키마에는 모든 객체와 각각의 필드가 정확하게 정의되어야 한다.
type Hero {
  name: String,
  friends: [Friend],
  power: Int
  
}
type Friend {
  name: String,
  relation: String
  
}
type Villain {
  name : String
  movie : String,
  age: Int
}

🔆 GraphQL 핵심 개념

Query/Mutation

  • Query
    • 데이터를 단순히 받아올 때 주로 사용. CRUD 에서 Read에 해당하는 기능
    • HTTP의 GET과 비슷
    • 여러개의 Query를 요청했을 때 쿼리가 병렬로 실행됨
  • Mutation
    • 데이터 조작하는 쿼리에 주로 사용. CRUD에서 Create, Update, Delete에 해당하는 기능
    • HTTP의 POST와 비슷
    • 여러개의 Mutation을 요청했을 때 쿼리가 순차적으로 실행됨 (한 요청에 두개의 Mutation이 있는경우 순차적 실행)

오퍼레이션

  • 일반 쿼리
    • 변수를 직접 입력
    • 특징란에서 예시로 든것이 일반 쿼리
  • 오퍼레이션
    • 쿼리용 함수 라고 생각하면 됨
    • 프로그래밍으로 변수에 값을 할당 할 수 있는 함수 인터페이스가 존재
    • 이 개념 덕분에 REST API를 호출할때와 다르게, 한번의 인터넷 네트워크 왕복으로 원하는 모든 데이터를 가져 올 수 있다.

Operation 을 사용한 Request

query HeroNameAndFriends {
  hero {
    name
    friends {
      name
    }
  }
}

Response

{
  "data": {
    "hero": {
      "name": "R2-D2",
      "friends": [
        {
          "name": "Luke Skywalker"
        },
        {
          "name": "Han Solo"
        },
        {
          "name": "Leia Organa"
        }
      ]
    }
  }
}

🙃 기존 REST API 통신의 한계

  • 특정 기능을 위해 여러번 API가 호출됨
  • 특정 요청에 Fit한 응답을 돌려주기 위해 API를 새로 만들어야함
  • API 유지보수의 어려움 (iOS, Android에 따라 일일이 API 따로 구현해야함)

🙂 장점

  • 하나의 Endpoint로 한번의 요청으로 여러 API의 정보를 가져올 수 있다
  • 필요한 데이터만 요청할 수 있다
  • DTO 여러개 불필요
  • 응답 Size를 줄일 수 있다
  • 기종에 상관없이 표준화된 API 개발 가능
  • 응답 객체의 Depth가 깊은 경우에도 원하는 데이터만 요청할 수 있다.

🙁 단점

  • GraphQL 스키마에서 필드를 정확하게 모두 명시해줘야하므로 번거로운 상황이 생긴다
    • DTO는 상속을 통해 필드 생략이 가능한데, GraphQL 스키마에서 필드 상속 또는 필드 생략할 수 없어서 필드를 모두 다 적어줘야한다
    • Map, Object를 사용하지 못한다
    • 하나의 필드만 담겨있어도 모든 응답을 객체로 만들어야 한다.
      • REST API는 ResponseEntity, HashMap<String,Any>로 유연하게 리턴 가능한데, GraphQL은 [Friend] List<Friend>라는 의미 이런식으로 정확히 정의해야한다.
    • DTO의 필드명이 변경되면 GraphQL 스키마 필드를 수정해줘야한다
  • 파일업로드
    • GraphQL은 원칙적으로 multipart/from-data 형식을 받을 수 없고 application/json 형식만 받을 수 있음
    • GraphQL에서는 multipart -> json으로 바꿔 전달해주는 미들웨어나 패키지를 사용해야하기 때문에 까다로움
  • Client에서도 모든 필드를 작성해야한다
    • Client에서 스키마를 가지고 있어야 요청할 수 있다.
    • Backend에서 필드 수정이 일어나면 Client도 다시 배포해야한다
    • 즉, 장점에서 백엔드/프론트엔드간 커플링 감소되어 유연성 증가한다고 써놨지만, 둘 다 동일한 스키마를 가지고 있어야 한다는 점에서는 여전히 커플링 되어있다고 할 수 있다.
  • 필드 타입(스칼라 타입)이 한정적이다
  • BackEnd 입장에서 설정해줄게 너무 많다.
    • Query/Mutation 파일에 작성한 메서드 및 리턴타입과 스키마 파일을 무조건 동기화 시켜야하기 때문에 REST API 보다 작성할 파일이 더 많다.

👆장단점 총평

GraphQL은 프론트엔드 입장에서 개발하기 편한 통신방식인 것 같다.

보통 REST API로 개발하게 될 경우 API 리턴값 형식(DTO)을 바꾸기 위해서는 백엔드 개발자가 코드를 변경해줘야한다. 하지만 GraphQL은 원하는 데이터만 쿼리 조회를 하듯 받아올 수 있기 때문에 응답 사이즈를 최소화 한 채로 요청할 수 있다. (프론트엔드, 백엔드 커플링 감소)

특히, 응답 객체의 Depth가 깊은 경우 반복문으로 파싱 및 필터링 해주는 과정을 생략할 수 있어 장점이 크게 체감된다. (이건 백엔드 개발자에게도 큰 장점이다)

하지만 백엔드 개발자로서는 REST API보다 좀 더 설정할게 많고, 스키마 파일도 작성해야해서 조금 번거로운 부분이 있었다. 또한 파일업로드 구현이 좀 번거롭고, 필드 타입이 한정적이여서 겪은 어려움도 있었다.

하지만 Depth가 깊은(4~5개의 깊이를 객체가 있었다)객체를 구현할 때에는 편리했다. 이걸 일일이 프론트엔드 요청에 맞게 DTO를 만들어 각각 다른 API를 만들었으면 번거로웠을 것 같다.

profile
DevOps를 살짝 찍먹하는 BackEnd 개발자

2개의 댓글

comment-user-thumbnail
2024년 3월 15일

정리 감사합니다:)

답글 달기
comment-user-thumbnail
2024년 5월 9일

공유 감사합니다!

답글 달기