GraphQL - Graphene: 4(Types Reference: Enums & Interfaces)

combi_jihoon·2022년 4월 28일
0

GraphQL

목록 보기
11/16
post-thumbnail

Enums

  • Enum은 unique, constant 값을 설정하기 위해 사용하는 GraphQL 타입이다.
    - 아래와 같이 Episode enum class를 만들 수 있다.

    방법 1

    import graphene
    
     class Episode(graphene.Enum):
        NEWHOPE = 4
        EMPIRE = 5
        JEDI = 6

    방법 2

    Episode = graphene.Enum('Episode', [('NEWHOPE', 4), ('EMPIRE', 5), ('JEDI', 6)])
  • 만약 사용하려는 Enum이 이미 정의되어 있다면 Enum.from_enum 함수를 이용해 재사용 할 수 있다.
    방법 1

    graphene.Enum.from_enum(AlreadyExistingPyEnum)

    방법 2

        # 람다 함수 이용
    graphene.Enum.from_enum(
        AlreadyExistingPyEnum,
            description=lambda v: return 'foo' if v == AlreadyExistingPyEnum.Foo else 'bar'
        )

Interfaces

  • Interface는 특정 타입이 반드시 포함해야 하는 필드를 정의해 놓은 일종의 abstract type(추상 타입)이다.
  • 즉, 필드 A, B, C가 포함된 interface I를 구현했을 경우 해당 interface로부터 구현된 타입은 반드시 필드 A, B, C를 포함해야 한다.
    - 다른 필드를 추가하는 것은 가능하지만 interface에 있는 필드를 제외하는 것은 불가능하다.

Interface

import graphene

class Character(graphene.Interface):
    id = graphene.ID(required=True)
    name = graphene.String(required=True)
    friends = graphene.List(lambda: Character)

타입 구현

  • 아래와 같이 Human, Droid의 두 가지 타입을 구현할 때 interface로 Character를 사용하는 경우 Human, Droid 타입 각각은 id, name, friends 세 필드를 반드시 포함하게 된다.
  • 각각 추가 필드로 starships, home_planetprimary_function을 갖는다.
class Human(graphene.ObjectType):
    class Meta:
        interfaces = (Character, )

    starships = graphene.List(Starship)
    home_planet = graphene.String()

class Droid(graphene.ObjectType):
    class Meta:
        interfaces = (Character, )

    primary_function = graphene.String()

스키마

  • 그러면 스키마는 episode에 따라 hero 필드의 타입을 결정할 수 있다.
  • 즉, episode가 5면 Human 타입을 반환하게 되며 해당 타입은 Character interface로 구현되어 있다.
    - 따라서, 반드시 가져야 하는 필드가 있다.
class Query(graphene.ObjectType):
    hero = graphene.Field(
        Character,
        required=True,
        episode=graphene.Int(required=True)
    )

    def resolve_hero(root, info, episode):
        # Luke is the hero of Episode V
        if episode == 5:
            return get_human(name='Luke Skywalker')
        return get_droid(name='R2-D2')

schema = graphene.Schema(query=Query, types=[Human, Droid])

Interface 사용시 data objects를 types로 resolve 하기

  • Graphene 사용시 주의할 점은 resolve_type을 정의하지 않으면 GraphQL types가 아니라 장고에서 사용하는 Graphene type에 대한 instance를 반환하게 된다는 것이다.
    - 이는 ObjectType과 Scalar 필드를 사용할 때는 문제가 없지만 interface를 사용하면 격게 될 문제이다.
  • 이러한 문제가 생기는 이유는 Grapehene이 interface를 resolve 하려면 data object를 Graphene type으로 변환하기 위한 충분한 정보가 있어야 하는데 정확한 명시를 해주지 않으면 Grapehen은 이러한 정보를 갖고 있지 않기 때문이다.
  • 따라서, 아래와 같이 classmethodresolve_type을 정의하는 것이 좋다.
    - 이를 통해 데이터 객체를 Graphene type으로 연결할 수 있다.

Interface with resolve type 예시

class Character(graphene.Interface):
    id = graphene.ID(required=True)
    name = graphene.String(required=True)

    @classmethod
    def resolve_type(cls, instance, info):
        if instance.type == 'DROID':
            return Droid
        return Human
profile
쿄쿄

0개의 댓글