1-2-2. Strawberry graphql 지원 유형 ( #Supported #types )

지원되는 타입

GraphQL은 아래와 같은 타입을 지원한다.

  • 스칼라 타입 (Scalar types)
  • 개체 타입 (Object types)
  • 쿼리 타입 (The Query type)
  • 뮤테이션 타입 (The Mutation type)
  • 입력 타입 (Input types)

스칼라 타입 (Scalar types)

스칼라 타입은 Python 의 기본 타입과 유사하다.

  • Int: 32비트 정수 integer는 Python의 int에 매핑
  • Float: Python의 float에 매핑
  • String: 파이썬의 str에 매핑
  • Boolean(참 또는 거짓)은 파이썬의 bool에 매핑
  • 고유 식별자 ID는 문자열로 직렬화되고 다음과 같이 사용 가능 strawberry.ID(“value”) 개체를 가져오거나 캐시의 키로 사용됨
  • UUID, 문자열로 직렬화된 UUID 값

@ Strawberry는 날짜, 시간 및 날짜/시간 개체에 대한 지원을 포함하고 있다. 공식적으로 GraphQL 사양에는 포함되어 있지 않지만 대부분 서버에서 지원하고 있다. ISO-8601 (날짜와 시간과 관련된 데이터 교환을 다루는 국제 표준) 로 일련번호가 지정되어 있다.

기초 적인 스칼라 타입의 요소로도 작동하지만 고유한 스칼라 타입을 지원한다.

개체 타입(The Query type)

GraphQL 스키마에서 정의하는 대부분의 타입은 객체 타입이고 개체 타입에는 필드 모음이 포함되며 각 필드는 스칼라 타입 이나 다른 개체형일 수 있다.

Tip. "개체 타입"은 이전 스키마 에서와 같이 서로를 참조할 수 있다.

import typing
import strawberry


@strawberry.type
class Book:
    title: str
    author: "Author"


@strawberry.type
class Author:
    name: str
    books: typing.List[Book]

필드에 데이터 제공

위의 스키마에서 Book에는 author필드가 있고 Author에는 books 필드가 있지만 해당 스키마의 구조를 실행하기 위해 데이터를 어떻게 매핑 하는지가 이해가 안될 수 있다.

이부분에서 함수를 통해 필드에 일부 데이터를 제공 하는 리졸버 를 사용한다.

Book 과 Author에 대한 이이해를 돕기위해 아래 예제 처럼 필드에 값을 제공하도록 리졸버를 작성한다.

def get_author_for_book(root) -> "Author":
    return Author(name="Michael Crichton")


@strawberry.type
class Book:
    title: str
    author: "Author" = strawberry.field(resolver=get_author_for_book)


def get_books_for_author(root):
    return [Book(title="Jurassic Park")]


@strawberry.type
class Author:
    name: str
    books: typing.List[Book] = strawberry.field(resolver=get_books_for_author)


def get_authors(root) -> typing.List[Author]:
    return [Author(name="Michael Crichton")]


@strawberry.type
class Query:
    authors: typing.List[Author] = strawberry.field(resolver=get_authors)
    books: typing.List[Book] = strawberry.field(resolver=get_books_for_author)

strawberry.field 요청 시 GraphQL 쿼리에 데이터를 렌더링하는 기능을 제공하며 GraphQL API의 기본 기능에 속한다.

예시의 데이터가 정적이어서 예가는 간단 할 순 있다 그러나 보다 복잡한 API를 구축할 때 리졸버는 SQLAlchemy를 사용하여 SQL 쿼리를 만들고 aiohttp 등을 사용하여 HTTP 요청을 만드는 다른 API에서 데이터베이스의 데이터를 매핑하도록 작성할 수 있다.

(자세한 내용은 리졸버 섹션 을 참조)

쿼리 타입 (The Query type)

타입은 Query클라이언트가 데이터에 대해 실행할 수 있는 GraphQL 쿼리(즉, 읽기 작업)를 정확하게 정의할 수 있다. (객체 타입과 유사하지만 이름은 항상 Query임)

타입의 각 필드는 Query로 지원되는 다른 쿼리의 이름과 반환 타입을 정의한다. (클라이언트에서 가장 많이 호출하게 될듯)

@strawberry.type
class Query:
    books: typing.List[Book]
    authors: typing.List[Author]

이 쿼리는 Book 과 Author 라는 쿼리를 정의한다. 각 쿼리는 List 로 리턴 하는 것을 할 수 있다.

tip. REST API에서는 Book 과 Author 가 서로 다른 엔드포인트(예: /api/books 및 /api/authors)에서 결과를 리턴한다. GraphQL은 단일 요청으로 두 리소스 모두 쿼리가 가능 하다.

쿼리 구조화

클라이언트에서 실행할 쿼리를 작성할 때 해당 쿼리는 스키마에서 미리 정의한 개체 타입의 형태와 일치 함을 알 수 있다.

지금까지 예제(쿼리 및 리졸버)를 기반으로 클라이언트에서 Book 과 Author 목록을 모두 요청하는 쿼리를 실행가능함을 알 수 있다.

# 쿼리 요청 
query {
  books {
    title
  }

  authors {
    name
  }
}

그런 다음 서버는 다음과 같이 쿼리 구조와 일치하는 결과로 쿼리에 응답합니다.

// 응답 내용 JSON
{
  "data": {
    "books": [{ "title": "Jurassic Park" }],
    "authors": [{ "name": "Michael Crichton" }]
  }
}

경우에 따라 이 두 리스트를 각각 가져오는 것이 유용할 수도 있지만 클라이언트는 각 books 의 author가 결과에 포함된 단일 책 목록을 가져오는 것을 선호할 수도 있다.

스키마의 Book 타입에는 Author 타입의 작성자 필드가 있으므로 클라이언트는 다음과 같이 쿼리를 구성이 가능하다

query {
  books {
    title
    author {
      name
    }
  }
}
// 응답 내용 JSON
{
  "data": {
    "books": [
      { "title": "Jurassic Park", "author": { "name": "Michael Crichton" } }
    ]
  }
}

뮤테이션 (The Mutation type)

Mutation 은 Query 와 구조 및 목적이 유사하지만 쿼리는 데이터의 리딩을 반면 Mutation은 쓰기 작업을 할때 쓰인다.

ARGS로 보이는 필드의 타입은 입력 및 반환 타입을 사전에 정의 한다.

@strawberry.type
class Mutation:
    @strawberry.field
    def add_book(self, title: str, author: str) -> Book:
        ...

addBook을 통해서 두 개의 ARGS (제목 및 저자)를 수락하고 새로 생성된 Book 을 반환한다. 예상은 했겠지만 이 -> Book (개체)은 스키마에서 미리 정의한 구조에서 리턴 한다

@참고 Strawberry는 스네이크 케이스를 카멜 케이스로 필드 이름을 변환한다. ( 코드 : add_books / 클라이언트 : addBooks )

뮤테이션 구조화

쿼리와 마찬가지로 변형은 스키마의 타입 정의 구조와 일치하는것을 확인할 수 있으며 다음 예제는 새 Book을 title 과 author만들고 생성된 객체의 특정 필드를 반환 값으로 요청하는 예제이다.

mutation {
  addBook(title: "Fox in Socks", author: "Dr. Seuss") {
    title
    author {
      name
    }
  }
}

쿼리와 마찬가지로 GraphQL 서버는 다음과 같이 뮤테이션에서 요청 했던 리턴 형태와 일치하는 결과로 응답한다.

{
  "data": {
    "addBook": {
      "title": "Fox in Socks",
      "author": {
        "name": "Dr. Seuss"
      }
    }
  }
}

입력 타입 (Input types)

입력 타입은 객체를 쿼리 및 변형에 대한 인수로 전달할 수 있는 특수 객체 타입이다

(스칼라 타입만 전달하는 것과 반대)

입력 타입을 선언 한는것은 무결성 검사시에 매우 유용하다

@strawberry.type
class Mutation:
    @strawberry.field
    def add_book(self, title: str, author: str) -> Book:
        ...

두 개의 인수를 허용하는 대신 이 뮤테이션은 모든 필드를 포함하는 단일 입력 타입을 허용 한다.

입력 타입의 정의는 객체 타입의 정의와 유사하지만 입력 키워드를 사용합니다.

@strawberry.input
class AddBookInput:
    title: str
    author: str


@strawberry.type
class Mutation:
    @strawberry.field
    def add_book(self, book: AddBookInput) -> Book:
        ...

이렇게 하면 스키마 내에서 AddBookInput 타입을 쉽게 전달할 수 있을 뿐만 아니라 GraphQL 지원 도구에 의해 자동으로 노출되는 설명으로 필드에 주석을 달기 위한 기반도 제공한다.

@strawberry.input
class AddBookInput:
    title: str = strawberry.field(description="The title of the book")
    author: str = strawberry.field(description="The name of the author")

여러 작업에 정확히 동일한 정보 집합이 필요한 경우 입력 타입이 유용할 수 있다 하지만 재사용은 자재 하길 바란다.

댓글

이 블로그의 인기 게시물

북궐도 2.0

Python Strawberry GraphQL 예제 (feat. #sqlmodel, #mysql)

Arch 계열 리눅스 구글 크롬 설치