GraphQL 기본 정리

sun202x·2022년 10월 6일
0

GraphQL

목록 보기
1/2
post-thumbnail

graphQL은 API를 위한 쿼리 언어이며 타입 시스템을 사용하여 쿼리를 실행하는 서버사이드 런타임이다. 특정 데이터베이스나 특정한 스토리지 엔진과 관계되어 있지 않으며 기존 코드와 데이터에 의해 대체된다.

graphQL에서 graph가 붙은 이유는 데이터 구조를 graph 구조의 관점으로 보고 있어서이다. 예를 들어 아래와 같이 데이터가 있다고 했을 때

{
	person: {
    	name: 'gildong'
        gender: 'man',
        job: 'thief'
    }
}

각 필드는 정점(node)을 나타내고 중괄호는 해당 필드의 간선을 나타내는 역할을 한다.
그렇기 때문에 person이라는 필드는 각각 name, gender, job이라는 필드와 연결된 형태의 graph 구조가 된다. 필드들의 관계(1:1, 1:n, n:m)를 나타내는 것은 책을 통해 자세히 보길 바란다.

GraphQL이 나오게 된 배경과 REST API의 단점

graphQLREST API를 대체하기 위해 처음 나온게 아니라 REST API의 단점을 보완하기 위해 등장했다고 한다. REST API가 처음 나왔을 때 굉장히 유용했지만, 사용하다 보니 특정 상황들에서 불편함이 커져갔다고 한다.

1. 오버페칭(over fetching)

REST API를 통해 데이터 요청을 하다보면 필요 이상의 데이터를 가져오는 경우가 생기기 시작했다.

2. 언더페칭(under fetching)

기존 API에 필요한 데이터를 추가해서 받고 싶은 경우 API를 추가로 요청해야 하는 경우가 잦아졌다.

3. 엔트리 포인트 관리

위 1, 2번 경우가 자주 생겨 클라이언트 요구사항이 들어오면 매번 엔트리 포인트를 추가하고 관리해주어야 한다.

위와 같은 단점들 때문에 이를 해소하기 위해 graphQL이 등장하게 되었고 불편함을 해소하기 위해 나왔던 API는 이제 완전히 REST API를 대체하게 되었다.

GraphQL 기본 개념

작업타입

graphQL의 작업 타입을 통해 현재 쿼리의 역할을 지정할 수 있다. 각 작업 타입들은 스키마 작성시 root 타입을 정의할 수 있다.

스키마 작성과 관련된 내용은 다음 포스트에서 다루도록 하겠다.

제공되는 작업 타입들은 아래와 같다.

query

데이터를 가져오기 위한 전반적인 행위를 뜻한다. 이론적으로는 query타입을 통해서도 데이터를 변경할 수 있지만 사용하지 않는 것이 좋다.

mutation

mutation은 사용자가 어플리케이션에서 데이터를 조작할 수 있는 모든 행위를 뜻한다. 해당 타입은 백엔드 데이터에 직접적으로 영향을 줄 수 있기 때문에 반드시 그것을 인지하고 작성해야 한다.

다중필드
mutationquery와 마찬가지로 여러 필드를 포함한다. 다만 주의해야 할 점은 query 필드는 병렬로 실행 되지만 mutation 필드는 하나씩 차례대로 실행된다는 것 이다.
하나의 요청에 두 개의 mutation을 보내면 첫 번째는 반드시 두 번째 실행전에 완료되는 것이 보장된다.

subscription

데이터 추가, 변경을 구독하기 위한 행위이다. 실시간 데이터 반영을 해야 할 때 유용하게 쓸 수 있다. subscription이 시작되면 웹소켓이 열리고 서버와 통신하게 된다. query, mutation과 다르게 subscription은 계속 열려 있기 때문에 필요하지 않은 시점에 해지 해주어야 한다.

필드

graphQL은 쿼리를 작성하여 원하는 필드를 가져올 수 있다. 각 필드들은 하위 필드를 작성할 수 있으며 하위 필드로 객체 타입, 스칼라 타입이 올 수있다. 또한 연관된 객체와 필드를 가져올 수 있기 때문에 여러번 서버에 요청할 필요가 없이 필요한 데이터를 손쉽게 가져올 수 있다.
이러한 특징 때문에 쿼리 작성시 단일 아이템 또는 배열에 상관없이 동일한 형태로 작성이 가능하다. 필드는 스키마를 기반으로 작성되기 때문에 필드를 보고 반환받을 데이터의 구조를 예상하기 쉽다.

인자

graphQL은 필드에 인자를 전달할 수 있다. REST API는 단일 인자들만 전달가능하지만 graphQL은 모든 필드와 중첩된 객체에 인자 전달이 가능하다. 또한 인자들은 다양한 타입으로 넘겨주는 것이 가능하다.

{
  human(id: "1000") {
    name
    height
  }
}

별칭

쿼리를 작성하다 보면 종종 동일 필드를 각각 가져와야 할 때가 있는데, 이 때 유용한 기능이 별칭 지정이다. 각 필드의 별칭을 지정하여 원하는 명칭으로 가져오는 것이 가능하다.

{
  empireHero: hero(episode: EMPIRE) {
    name
  }
  jediHero: hero(episode: JEDI) {
    name
  }
}

프래그먼트

필요한 필드셋을 정의하여 재사용 할 수 있는 단위를 프래그먼트라고 한다. 복잡한 필드셋들이 반복 된다면 프래그먼트로 정의하여 재사용하는 것이 좋다.
복잡한 응용 프로그램의 데이터 요구사항을 작은 단위로 분할하는데 사용하며, 특히 청크가 다른 ui 구성 요소를 하나의 초기 데이터 fetch로 통합하는 경우 많이 사용한다고 한다. 프래그먼트 안에서도 변수 사용이 가능하다.

{
  leftComparison: hero(episode: EMPIRE) {
    ...comparisonFields
  }
  rightComparison: hero(episode: JEDI) {
    ...comparisonFields
  }
}

fragment comparisonFields on Character {
  name
  appearsIn
  friends {
    name
  }
}

변수

graphQL은 클라이언트 단에서 동적 값을 전달하기 위해 변수 기능 제공한다.

  1. 동적 값을 $variable로 작성
  2. $variable을 쿼리에서 받는 변수로 선언
  3. 별도의 전송규약 변수에 variableName: value을 전달

주의할 점은 사용자가 제공한 값으로 문자열 보간을 사용해서는 안된다는 것이다. ! 키워드를 통해 필수여부를 지정할 수 있다. 또한 = 키워드를 통해 기본 값 적용도 가능하다.

필수값 설정
$variable: !Variable

기본값 적용
$variable: Variable =DEFAULT

지시어

변수를 사용하여 쿼리의 구조나 형태를 동적으로 변경하는데 사용하며, 필드나 프래그먼트 안에 삽입될 수 있다. 코어 graphQL에는 두가지 지시어 사양을 제공하고 있다.

인자가 true인 경우에만 필드를 결과에 포함한다.
@include(if: Boolean)

인자가 true이면 해당 필드를 건너 뛴다.
@skip(if: Boolean)

필드를 추가, 제거하기 위해 문자열(쿼리)을 조작해야 하는 상황에서 유용하게 쓰인다. 지시어는 서버에 새로운 형태를 정의하여 실험적인 기능을 추가할 수도 있다.

인라인 프래그먼트

graphQL 스키마에는 인터페이스나 유니온 타입을 정의하기 위해 인라인 프래그먼트를 제공한다. 특정 조건에 따라 반환받을 타입이 달라질 경우 인라인 프래그먼트를 사용할 수 있다. …on 키워드를 통해 특정 타입 조건을 걸 수도 있다.

query HeroForEpisode($ep: Episode!) {
  hero(episode: $ep) {
    name
    ... on Droid {
      primaryFunction
    }
    ... on Human {
      height
    }
  }
}

인트로스펙션(introspection)

쿼리를 통해 API 세부 스키마 정보를 조회하기 위해 제공된다. 특정 메타 필드를 통해 원하는 스키마 정보를 가져올 수 있다.

__schema 필드를 통해 API에 존재하는 모든 스키마 정보를 확인할 수 있다.

query {
  __schema {
  	types {
      name
      description
    }
  }
}

__type 필드를 통해 넘겨받은 인수에 해당하는 필드 스키마 정보를 확인할 수 있다.

query lifetDetails {
  __type(name: "Lift") {
  	name
    fields {
      name
      description
      type {
      	name
      }
    }
  }
}

__typename 필드를 통해 현재 시점에 요청한 필드의 타입명을 알 수 있다.

{
  search(text: "an") {
    __typename
    ... on Human {
      name
    }
    ... on Droid {
      name
    }
    ... on Starship {
      name
    }
  }
}

Reference

GraphQL 공식 문서
웹 앱 API 개발을 위한 GraphQL

profile
긍정적으로 살고 싶은 개발자

0개의 댓글