Schemas and Types

이정훈·2024년 10월 8일

GraphQL

목록 보기
6/13

여기서는 GraphQl의 타입 시스템과 이 시스템이 어떻게 쿼리될 수 있는 데이터들을 명시하는지 알아보겠습니다.

Type system

쿼리를 할 때 어떤 필드를 우리가 선택할 수 있는지 어떤 객체가 반환되는지 서브 객체로 어떤 필드가 가능한지에 대한 정확한 묘사는 유용합니다.

모든 GraphQL 서비스는 쿼리 가능한 데이터에 대한 집합들을 정의합니다.
그렇기 때문에 쿼리가 왔을 때 스키마를 통해 해당 쿼리를 검증하고 실행합니다.

Type language

GraphQL 서비스는 어떤 언어로도 작성이 가능합니다.
GraphQL이 특정 언어에 의존하지 않기 때문입니다.

Object types and fields

GraphQL 스키마에서 가장 간단한 형태의 컴포넌트는 객체 타입입니다.
객체 타입은 서비스로부터 가져올 수 있는 객체에 대한 정보를 제공합니다.

GraphQL 스키마 언어에서 아래와 같이 표현될 수 있습니다.

type Character {
  name: String!
  appearsIn: [Episode!]!
}

위에 대한 설명을 해보자면
Character타입을 정의하고 있습니다.
해당 Character타입은 name과 appearsIn이라는 필드를 가집니다.
name필드는 String타입이며 null이 허용되지 않습니다.
appearsIn은 배열 타입이며 해당 배열에는 Episode 타입의 값을 가집니다. 이때 Episode는 null이 되지 못하고 배열 자체도 null이 되지 못합니다.

Arguments

GraphQL의 객체 타입은 모든 필드에 대해 0개 이상의 인자를 가질 수 있습니다.
아래는 예시입니다.

type Starship {
  id: ID!
  name: String!
  length(unit: LengthUnit = METER): Float
}

length쪽에 인자를 주고 있습니다.
해석을 해보면
unit이라는 변수를 받는데 해당 변수는 LengthUnit타입입니다.
또한 기본값으로 METER을 받습니다.

The Query and Mutation types

스키마 내부에서 존재할 수 있는 특별한 두 개의 타입이 있습니다.
알는 예시입니다.

schema {
  query: Query
  mutation: Mutation
}

스키마에서 query를 무조건 가지며 mutation의 경우 가질 수도 안 가질 수도 있습니다.
이 타입들은 정규 객체 타입들과 같습니다.
그러나 이들은 특별한데 이 타입들은 모든 GraphQL 쿼리에 대해 진입점을 정의하기 때문입니다.

아래와 같은 쿼리가 있다고 가정해 보겠습니다.

query {
  hero {
    name
  }
  droid(id: "2000") {
    name
  }
}
/// 결과
{
  "data": {
    "hero": {
      "name": "R2-D2"
    },
    "droid": {
      "name": "C-3PO"
    }
  }
}

위와 같은 쿼리가 가능한 이유는 아래와 같은 Query타입이 존재하기 때문입니다.

type Query {
  hero(episode: Episode): Character
  droid(id: ID!): Droid
}

Mutation에 대해서도 유사하게 작동합니다.

Scalar types

GraphQL 객체 타입은 이름과 필드들을 가집니다.
이떄 그 필드들이 구체적인 데이터로 변환되어야 합니다.
이 과정에서 스칼라 타입이 필요합니다.
스칼라 타입은 쿼리에서 최종적으로 반환되는 구체적인 데이터를 말합니다.

기본적인 스칼라 타입으로는 Int, Float, String, Boolean, ID가 있습니다.

또한 사용자 정의 스칼라 타입을 만들 수 있습니다.
다음이 예시입니다.

scalar Date

Enumeration types

Enum이라 불리는 타입은 특별한 형태의 Scalar type입니다.
이 타입은 특정 집합 내에 속해 있는 값들만을 허용합니다.

이 타입을 이용하면 아래와 같은 일들이 가능합니다.
1. 인자로 들어온 값이 허용되는 값인지 검증할 수 있습니다.
2. 집합 내 값들만으로 소통이 된다는 것을 보증합니다.

아래는 enum을 정의하는 예시입니다.

enum Episode {
  NEWHOPE
  EMPIRE
  JEDI
}

Lists and Non-Null

GraphQL에서는 객체 타입과 Scalra타입 그리고 enum 타입이 유일하게 정의할 수 있는 타입입니다.

하지만 추가적인 type 변경자를 사용할 수 있습니다.
아래는 !를 이용한 예시입니다.

type Character {
  name: String!
  appearsIn: [Episode]!
}

!가 붙은 타입은 null은 반환하지 않는다는 것을 뜻합니다.

이번에는 List에서 !가 어떻게 작동하는지 알아보겠습니다.
아래와 같은 list가 있다고 가정합시다.

myField: [String!]

myField는 배열을 가지고 해당 배열의 값들을 String이여야 합니다.
null은 허용하지 않습니다.
그러나 배열자체가 null인 것은 허용합니다.
그럼 배열 자체가 null이 안되게 하려면 어떻게 해야할까요?

아래와 같이 해주면 됩니다.

myField: [String]!

이제 myField는 배열이지만 null은 될 수 없습니다.
배열 안의 값들은 null이거나 String가 될 수 있습니다.

만약 배열 자체도 그리고 배열의 값도 null이 될 수 없게 하고 싶다면 아래와 같이 하면 됩니다.

myField: [String!]!

Interfaces

GraphQL은 인터페이스를 지원합니다.
아래는 인터페이스를 정의하는 예시입니다.

interface Character {
  id: ID!
  name: String!
  friends: [Character]
  appearsIn: [Episode]!
}

이 인터페이스를 구현하는 타입들은 인터페이스에 명시된 것들을 무조건 가지고 있어야 합니다.
아래는 예시입니다.

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
}

Union types

GraphQL은 유니온 타입도 지원합니다.
유니온 타입은 여러 타입의 집합 내에서 어느 타입이 할당되어도 괜찮은 타입입니다.
아래는 예시입니다.

union SearchResult = Human | Droid | Starship

Input types

지금까지는 enum이나 string을 필드의 인자로 주었습니다.
하지만 이보다 복잡한 객체도 인자로 줄 수 있습니다.
이는 mutation에서 유용합니다.
이를 위해 type대신 input 키워드로 대신 써야합니다.
아래는 예시입니다.

input ReviewInput {
  stars: Int!
  commentary: String
}

위 input 타입을 이용한 mutation예시입니다.

mutation CreateReviewForEpisode($ep: Episode!, $review: ReviewInput!) {
  createReview(episode: $ep, review: $review) {
    stars
    commentary
  }
}
// 데이터 전달
{
  "ep": "JEDI",
  "review": {
    "stars": 5,
    "commentary": "This is a great movie!"
  }
}
profile
기록으로 흔적을 남깁니다.

0개의 댓글