ABCD의 GraphQL 첫 날 02

GraphQL Study02

GraphQLtype

  • GraphQLSDL(Schema Definition Language)로, 스키마 우선 주의가 적용
  • query에 사용할 필드는 API 스키마에 정의되어야 한다

  • 정의되는 곳은 서버이며, 타입 하나가 하나의 작업을 의미

root Type

아래의 타입 작업은 쿼리 문서의 루트에서 이루어진다.

일반 객체 타입과 동일하지만 모든 GraphQL 쿼리의 진입점(entry point) 을 정의

  • Query
    • 모든 GraphQL 서비스가 지닌 타입
  • Mutation
  • Subscription

img

기본적으로 내장된 스칼라 type

이들의 해석은 스칼라 객체로 이루어지며, 쿼리 내에서 하위 선택 불가

  • String

  • Int

  • Float

  • Boolean

  • ID

    • ID 타입은 String과 같은 방법으로 직렬화되지만, ID 로 정의하는 것은 사람이 읽을 수 있도록 하는 의도가 아니라는 것을 의미

커스텀 스칼라 type

만약 추가적인 스칼라 타입을 쓰고자 한다면,

1
scalar DateTime

이런 식으로 위에 명시한 뒤

1
2
3
4
5
6
7
type Photo {
id: ID!
name: String!
url: String!
description: String
created: DateTime!
}

이렇게 사용

많은 사람들이 쓰는 스칼라 타입을 정의해놓은 모듈도 있다

객체 타입

  • GraphQL 스키마의 가장 기본적인 구성 요소
  • 필드가 있는 타입
  • 스키마의 대부분을 차지

열거형 타입 Enums

  • 타입의 인자가 허용된 값 중 하나임을 검증
  • 필드가 항상 값의 열거형 집합 중 하나가 될 것임을 타입 시스템을 통해 의사소통
1
2
3
4
5
enum Episode {
NEWHOPE
EMPIRE
JEDI
}

위의 필드는 NEWHOPE, EMPIRE, JEDI라는 String type만 지닐 수 있다

유니온

1
union SearchResult = Human | Droid | Starship

해당 타입은 Human, Droid, Starship 객체 중 하나가 리턴

Non-null

  • 값의 유효성 검사 가능

  • null이 아닌 값을 반환할 것을 기대 가능

    • null 발생 시 GraphQL 서버 실행 오류, 클라이언트 측은 오류를 응답 받음

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      {
      "errors": [
      {
      "message": "Variable \"$id\" of required type \"ID!\" was not provided.",
      "locations": [
      {
      "line": 1,
      "column": 17
      }
      ]
      }
      ]
      }

리스트

  • [INT]
    • INT type의 배열
    • 배열 자체가 null일 수 있다
    • 배열 안에 null이 들어갈 수 있다
  • [INT!]
    • INT type의 배열
    • 배열 자체가 null일 수 있다
    • 배열 안에 null이 들어갈 수 없다
  • [INT]!
    • INT type의 배열
    • 배열 자체가 null일 수 없다
    • 배열 안에 null이 들어갈 수 있다
  • [INT!]!
    • INT type의 배열
    • 배열 자체가 null일 수 없다
    • 배열 안에 null이 들어갈 수 없다
    • 보통 일대다 연결에 사용

인터페이스

구현하기 위해 타입이 포함해야하는 특정 필드들을 포함하는 추상 타입

1
2
3
4
5
6
interface Character {
id: ID!
name: String!
friends: [Character]
appearsIn: [Episode]!
}

아래의 인터페이스를 구현한 type은 해당 인자와 리턴 타입을 가진 정확한 필드를 지니게 된다

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
type Human implements Character {
id: ID!
name: String!
friends: [Character]
appearsIn: [Episode]!
starships: [Starship]
totalCredits: Int
}

type Droid implements Character {
id: ID!
name: String!
friends: [Character]
appearsIn: [Episode]!
primaryFunction: String
}

클라이언트 단에서 리턴 값으로 요청한 필드가 만약 interface의 필드가 아니라면(ex. totalCredits, primaryFunction) 반드시 인라인 프래그먼트를 요구

즉, 아래의 hero 타입은 Character type을 반환하는데, episode의 인자에 따라 Human 타입과 Droid 타입인지가 달라진다. 때문에 아래의 리턴 값으로 totalCredits, primaryFunction을 요청하라면 인라인 프래그먼트가 필요

1
2
3
4
5
query HeroForEpisode($ep: Episode!) {
hero(episode: $ep) {
name
}
}

이렇게

1
2
3
4
5
6
7
8
query HeroForEpisode($ep: Episode!) {
hero(episode: $ep) {
name
... on Droid {
primaryFunction
}
}
}

만약 hero의 리턴 타입이 Droid라면 nameprimaryFunction이 함께 리턴

input

  • 복잡한 객체를 인자로 전달하기 위한 목적으로 만들어진 객체

  • 특히 Mutation에서 사용이 많이 된다


  • 선언
1
2
3
4
input ReviewInput {
stars: Int!
commentary: String
}
  • 사용

    • 요청

      1
      2
      3
      4
      5
      6
       mutation CreateReviewForEpisode($ep: Episode!, $review: ReviewInput!) {
      createReview(episode: $ep, review: $review) {
      stars
      commentary
      }
      }
      • 파라미터 input

        1
        2
        3
        4
        5
        6
        7
        {
        "ep": "JEDI",
        "review": {
        "stars": 5,
        "commentary": "This is a great movie!"
        }
        }
  • 응답

    1
    2
    3
    4
    5
    6
    7
    8
    {
    "data": {
    "createReview": {
    "stars": 5,
    "commentary": "This is a great movie!"
    }
    }
    }