• 본 시리즈에서는 How to GraphQL의 Tutorial 문서들을 차례대로 번역합니다.
  • 이 글은 GraphQL Advanced - More GraphQL Concepts을 번역한 글입니다.
  • 오역 또는 의역이 있을 수 있습니다. 양해 부탁드리며, 수정할 필요한 부분은 댓글로 요청해주세요.

GraphQL 개념 더 알아보기

Fragment를 사용하여 재사용성 향상시키기

Fragment는 GraphQL 코드의 구조와 재사용성을 향상시키는 데에 도움을 주는 편리한 기능입니다. Fragment는 특정 타입의 필드들로 이루어진 집합입니다.

아래와 같은 타입을 가정합시다.

type User {
  name: String!
  age: Int!
  email: String!
  street: String!
  zipcode: String!
  city: String!
}

사용자의 주소와 관련된 모든 정보를 Fragment를 사용하여 아래와 같이 나타낼 수 있습니다.

fragment addressDetails on User {
  name
  street
  zipcode
  city
}

자, 사용자의 주소에 접근하는 쿼리를 작성한다면, 아래와 같은 문법을 사용하여 Fragment를 참조하고, 4개 필드를 직접 작성하는 수고를 덜 수 있습니다.

{
  allUsers {
    ... addressDetails
  }
}

위의 쿼리는 아래의 쿼리와 같은 의미를 갖습니다.

{
  allUsers {
    name
    street
    zipcode
    city
  }
}

인자를 사용하여 필드를 매개변수화

GraphQL에서 타입을 정의할 떄, 각 필드는 0개 이상의 인자(Argument)를 가질 수 있습니다. 타입이 있는 프로그래밍 언어에서는 함수에 인자를 전달할 수 있습니다. 이와 유사하게 각 인자는 이름타입을 가집니다. GraphQL에서는 인자에 기본값을 부여할 수도 있습니다.

예를 들어, 아주 초반에 다루었던 스키마를 다시 보도록 합시다.

type Query {
  allUsers: [User!]!
}

type User {
  name: String!
  age: Int!
}

이제 allUsers 필드에 인자를 추가하여 특정 연령 이상의 사용자만을 필터링하여 포함하도록 만들 수 있습니다. 또한 기본값을 부여하여, 인자가 전달되지 않을 경우 모든 사용자를 반환하도록 만들 수 있습니다.

type Query {
  allUsers(olderThan: Int = -1): [User!]!
}

여기서 사용된 olderThan 인자는 아래와 같은 문법을 사용하여 쿼리에 전달할 수 있습니다.

{
  allUsers(olderThan: 30) {
    name
    age
  }
}

Alias를 이용한 쿼리 결과의 명명

GraphQL의 중요한 강점 중 하나는 한번의 요청으로 다수의 쿼리를 전송할 수 있다는 것입니다. 하지만 요청되는 필드의 구조에 맞추어 응답 데이터의 구조가 형성되므로, 같은 필드에 대한 여러 쿼리를 전송할 경우 이름이 겹치는 문제가 발생할 수 있습니다.

{
  User(id: "1") {
    name
  }
  User(id: "2") {
    name
  }
}

다른 인자들을 사용하여 같은 필드에 대하여 요청한 것이므로 위와 같은 쿼리는 GraphQL 서버에서 오류를 발생시킵니다. 이러한 쿼리를 전송하려면 Alias를 사용해야 합니다. 예를 들어, 아래와 같이 쿼리 결과에 대하여 이름을 부여해야 합니다.

{
  first: User(id: "1") {
    name
  }
  second: User(id: "2") {
    name
  }
}

반환된 결과를 보면, 각 User 객체들이 지정된 Alias에 따라 이름지어진 것을 알 수 있습니다.

{
  "first": {
    "name": "Alice"
  },
  "second": {
    "name": "Sarah"
  }
}

SDL 심화

이전 장에서 다루었던 것 이외에도 SDL은 다양한 기능들을 제공합니다. 실제 예시를 사용하여 이에 대하여 논하도록 하겠습니다.

Object & Scalar 타입

GraphQL에는 두 가지 종류의 타입이 존재합니다.

  • 스칼라(Scalar) 타입은 실체가 있는 데이터 단위를 나타냅니다. GraphQL 명세는 String, Int, Float, Boolean, ID 등 총 5개의 스칼라 타입을 정의하고 있습니다.
  • 객체(Object) 타입은 해당 타입의 특성을 표현하는 필드들로 구성됩니다. 객체 타입의 예시로는 위에서 살펴본 User, Post 타입 등이 있습니다.

모든 GraphQL 스키마에서 고유한 스칼라 또는 객체 타입을 정의할 수 있습니다. 별도로 정의한 스칼라 타입의 대표적인 예시는 Date 타입으로, 이 타입을 구현할 때에는 타입의 유효성 검사, 직렬화, 역직렬화 방법 등을 모두 정의해야 합니다.

Enums 타입

GraphQL에서는 열거(Enumeration) 타입(줄여서 Enums)를 정의할 수 있습니다. Enums 타입이란 일정한 값들의 집합에 대하여 의미를 표현할 수 있는 언어 기능입니다. 이에 따르면 한 주의 요일들을 나타내기 위하여 Weekday라는 타입을 정의할 수 있습니다.

enum Weekday {
  MONDAY
  TUESDAY
  WEDNESDAY
  THURSDAY
  FRIDAY
  SATURDAY
  SUNDAY
}

기술적으로 볼 때 Enums는 스칼라 타입의 특별한 종류 중 하나라는 점을 유의하시기 바랍니다.

Interface

인터페이스(Interface)를 사용하면 타입을 추상적인 방식으로 설명할 수 있습니다. 인터페이스는 해당 인터페이스를 구현하는 타입이 반드시 가져야 하는 필드에 대하여 정의합니다. 대부분의 GraphQL 스키마에서 타입에는 id 필드가 필요합니다. 이러한 요구 사항은 해당 필드가 포함된 인터페이스를 정의하고, 모든 타입들이 이 인터페이스를 반드시 구현하도록 함으로써 충족될 수 있습니다.

interface Node {
  id: ID!
}

type User implements Node {
  id: ID!
  name: String!
  age: Int!
}

Union 타입

유니온(Union) 타입은 어떤 타입이 여러 타입 중 하나이어야 함을 나타낼 때에 사용합니다. 예시를 보면 쉽게 이해할 수 있습니다. 아래와 같은 타입을 생각해봅시다.

type Adult {
  name: String!
  work: String!
}

type Child {
  name: String!
  school: String!
}

이제, Person 타입을 정의할 때에 AdultChild의 Union으로 정의할 수 있습니다.

union Person = Adult | Child

이렇게 되면 또 다른 문제가 발생합니다. GraphQL 쿼리를 사용하여 Child에 대한 정보를 불러오려는 상황에서 Person 타입만이 사용 가능하다면, Child 타입의 필드가 사용 가능한지 여부를 어떻게 해야 알 수 있을까요?

답은 바로 조건부 Fragment에 있습니다.

{
  allPersons {
    name # `Adult`와 `Child` 모두 사용 가능합니다
    ... on Child {
      school
    }
    ... on Adult {
      work
    }
  }
}

Quiz

다음 중 옳지 않은 것은?

  • Alias는 다수 쿼리에 대한 결과 객체들을 각기 이름짓는 데에 사용된다.
  • Fragment는 GraphQL 코드의 구조와 재사용성을 향상시키는 데에 유용하다.
  • GraphQL 타입의 모든 필드는 0개 이상의 인자와 연관될 수 있다.
  • GraphQL은 내장 데이터 타입을 가진다.