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")
여러 작업에 정확히 동일한 정보 집합이 필요한 경우 입력 타입이 유용할 수 있다 하지만 재사용은 자재 하길 바란다.
댓글
댓글 쓰기