GraphQL и Strawberry
В REST форму ответа определяет endpoint. В GraphQL один endpoint, а клиент перечисляет нужные поля. Так пропадают лишние поля и лишние запросы, а типизированная схема описывает сама себя. Цена — более сложные кэширование, загрузка файлов и лимиты запросов.
Strawberry работает в подходе code-first: аннотации типов Python становятся схемой GraphQL. Установка:
pip install "strawberry-graphql[fastapi]"| GraphQL | Strawberry / Python |
|---|---|
type Book | @strawberry.type class Book |
input BookInput | @strawberry.input class BookInput |
ID! | strawberry.ID |
nullable String | str | None |
[Book!]! | list[Book] |
поле Query | @strawberry.field |
поле Mutation | @strawberry.mutation |
поле Subscription | @strawberry.subscription + AsyncGenerator |
💡 Заменять REST не обязательно. Роутер GraphQL может жить рядом с вашими эндпоинтами FastAPI.
Типы и запросы
import strawberry
@strawberry.type
class Book:
id: strawberry.ID
title: str
year: int
BOOKS = [
Book(id=strawberry.ID("1"), title="Notes", year=2020),
Book(id=strawberry.ID("2"), title="Kernel", year=2019),
]
@strawberry.type
class Query:
@strawberry.field
def books(self) -> list[Book]:
return BOOKS
schema = strawberry.Schema(query=Query)
result = schema.execute_sync("{ books { title year } }")
print(result.data)
# {'books': [{'title': 'Notes', 'year': 2020}, {'title': 'Kernel', 'year': 2019}]}execute_sync выполняет запрос без сервера, это удобно в тестах. Аргументы резолвера становятся аргументами GraphQL, а | None делает результат необязательным:
@strawberry.type
class Query:
@strawberry.field
def book(self, id: strawberry.ID) -> Book | None:
return next((b for b in BOOKS if b.id == id), None)