graphql_alchemy
Библиотека для типобезопасного построения GraphQL запросов из Python-моделей. Поддерживает преобразование dataclasses/ Pydantic/dict в GraphQL схемы.
Возможности
- ✅ Типобезопасное построение GraphQL запросов
- ✅ Поддержка трех типов моделей: dataclasses, Pydantic, словари
- ✅ Сложные вложенные структуры
- ✅ Автоматическая генерация схемы
- ✅ Входные параметры и переменные
- ✅ Валидация типов данных
Структура библиотеки
├── src/ # Исходный код библиотеки
│ ├── __init__.py
│ ├── const.py # Константы и настройки
│ ├── converter/ # Модули конвертации моделей в GraphQL
│ │ ├── __init__.py
│ │ ├── base.py # Базовый класс конвертера
│ │ ├── dataclass_.py # Конвертер для dataclasses
│ │ ├── dict_.py # Конвертер для словарей
│ │ └── pydantic_.py # Конвертер для Pydantic моделей
│ ├── types/ # Типы данных и классы GraphQL
│ │ ├── __init__.py
│ │ ├── base.py # Базовые классы типов
│ │ ├── enums.py # Перечисления (GraphQL методы и т.д.)
│ │ └── query.py # Классы для построения GraphQL запросов
│ └── utils.py # Вспомогательные функции
├── tests/ # Тесты библиотеки
│ ├── __init__.py
│ ├── fixtures/ # Фикстуры и тестовые данные
│ │ ├── __init__.py
│ │ ├── fuctions.py
│ │ └── queries.py # Примеры GraphQL запросов для проверки
│ ├── test_converter/ # Тесты конвертеров
│ │ ├── __init__.py
│ │ ├── test_base.py # Тесты базового конвертера
│ │ ├── test_dataclass.py # Тесты конвертера dataclasses
│ │ └── test_pydantic.py # Тесты конвертера Pydantic
│ ├── test_method.py # Тесты GraphQL методов
│ ├── test_query/ # Тесты построения запросов
│ │ ├── __init__.py
│ │ ├── test_dataclass.py # Тесты запросов из dataclasses
│ │ ├── test_dict.py # Тесты запросов из словарей
│ │ └── test_pydantic.py # Тесты запросов из Pydantic моделей
│ ├── test_query_generator.py # Тесты генератора запросов
│ └── test_utils.py # Тесты вспомогательных функций
├── README.md # Документация проекта
├── pyproject.toml # Конфигурация проекта и зависимости
└── uv.lock # Файл блокировки версий зависимостей (uv)
Быстрый старт
1. Использование с Dataclasses
from dataclasses import dataclass
from graphql_query import GraphQlQuery, GraphQlMethodType
from graphql_query.converter import dataclass_ as dataclass_converter
@dataclass
class User:
typename: str = "User"
id: int
name: str
email: str
@dataclass
class ReturnError:
typename: str = "ReturnError"
message: str
# Создание GraphQL запроса
query = GraphQlQuery(
type_method=GraphQlMethodType.query,
name="GetUser",
name_method="getUser",
inputs={"user_id": 123},
models=dataclass_converter.build_graph_ql_models([User, ReturnError]),
)
print(str(query))
Результат GraphQL:
query GetUser($user_id: Int!) {
getUser(user_id: $user_id) {
... on User {
id
name
email
}
... on ReturnError {
message
}
}
}
2. Использование с Pydantic
from pydantic import BaseModel, Field
from graphql_query import GraphQlQuery, GraphQlMethodType
from graphql_query.converter import pydantic_ as pydantic_converter
class User(BaseModel):
typename: str = Field(default="User", alias="__typename")
id: int
name: str
email: str
class UserInput(BaseModel):
user_id: int
# Создание запроса
query = GraphQlQuery(
type_method=GraphQlMethodType.query,
name="GetUser",
name_method="getUser",
inputs=UserInput(user_id=123).model_dump(),
models=pydantic_converter.build_graph_ql_models([User]),
)
print(str(query))
Результат GraphQL:
query GetUser($user_id: Int!) {
getUser(user_id: $user_id) {
id
name
email
}
}
3. Использование со словарями
from graphql_query import GraphQlQuery, GraphQlMethodType
from graphql_query.converter.dict_ import build_graph_ql_models
user_schema = {
"__typename": "User",
"id": 1,
"name": "John",
"email": "john@example.com"
}
query = GraphQlQuery(
type_method=GraphQlMethodType.query,
name="GetUser",
name_method="getUser",
inputs={"user_id": 123},
models=build_graph_ql_models([user_schema]),
)
print(str(query))
Расширенные примеры
Сложные вложенные модели
from dataclasses import dataclass
from typing import Optional, List
@dataclass
class Address:
city: str
street: str
zip_code: str
@dataclass
class Company:
name: str
address: Address
@dataclass
class User:
typename: str = "User"
name: str
email: str
company: Company
friends: List["User"]
# Автоматически генерирует вложенные GraphQL поля
query = GraphQlQuery(
type_method=GraphQlMethodType.query,
name="GetUserWithFriends",
name_method="getUser",
inputs={"user_id": 123},
models=dataclass_converter.build_graph_ql_models([User]),
)
print(str(query))
Результат GraphQL:
query GetUserWithFriends($user_id: Int!) {
getUser(user_id: $user_id) {
name
email
company {
name
address {
city
street
zip_code
}
}
friends {
name
email
company {
name
address {
city
street
zip_code
}
}
}
}
}
Пагинация и фильтрация
from dataclasses import dataclass
from typing import Optional, List
@dataclass
class Research:
title: str
description: str
status: str
@dataclass
class ResearchPagination:
typename: str = "ResearchPagination"
researches: List[Research]
pages: int
current_page: int
@dataclass
class FilterInput:
status: Optional[str] = None
date_from: Optional[str] = None
date_to: Optional[str] = None
@dataclass
class ResearchFilterInput:
pass
# Запрос с пагинацией и фильтрацией
query = GraphQlQuery(
type_method=GraphQlMethodType.query,
name="GetResearches",
name_method="researches",
inputs={
"filter": ResearchFilterInput(),
"page": 1,
"limit": 10
},
models=dataclass_converter.build_graph_ql_models([ResearchPagination]),
)
print(str(query))
Результат GraphQL:
query GetResearches($filter: ResearchFilterInput, $page: Int, $limit: Int) {
researches(filter: $filter, page: $page, limit: $limit) {
researches {
title
description
status
}
pages
current_page
}
}
Мутации с входными параметрами
from dataclasses import dataclass
from uuid import UUID, uuid4
@dataclass
class CreateUserInput:
name: str
email: str
password: str
@dataclass
class User:
id: UUID
name: str
email: str
@dataclass
class CreateUserResponse:
user: User
success: bool
message: str
@dataclass
class CreateUserInput:
typename: str = "CreateUserInput"
mutation = GraphQlQuery(
type_method=GraphQlMethodType.mutation,
name="CreateUser",
name_method="createUser",
inputs={"input": CreateUserInput()},
models=dataclass_converter.build_graph_ql_models([CreateUserResponse]),
)
print(str(mutation))
Результат GraphQL:
mutation CreateUser($input: CreateUserInput!) {
createUser(input: $input) {
user {
id
name
email
}
success
message
}
}
Union типы и обработка ошибок
from dataclasses import dataclass
from typing import Union
@dataclass
class User:
typename: str = "User"
id: int
name: str
email: str
@dataclass
class NotFoundError:
typename: str = "NotFoundError"
message: str
resource: str
@dataclass
class ValidationError:
typename: str = "ValidationError"
message: str
field: str
# Union тип для разных возможных ответов
UserResult = Union[User, NotFoundError, ValidationError]
query = GraphQlQuery(
type_method=GraphQlMethodType.query,
name="GetUserWithErrors",
name_method="getUser",
inputs={"user_id": 123},
models=dataclass_converter.build_graph_ql_models([User, NotFoundError, ValidationError]),
)
print(str(query))
Результат GraphQL:
query GetUserWithErrors($user_id: Int!) {
getUser(user_id: $user_id) {
... on User {
id
name
email
}
... on NotFoundError {
message
resource
}
... on ValidationError {
message
field
}
}
}
Сложные исследовательские модели (из тестов)
from dataclasses import dataclass, field
from uuid import UUID, uuid4
from typing import List, Optional
@dataclass
class Duration:
duration: int
duration_cost: float
duration_id: int
@dataclass
class ResearchCalc:
age_max: int
age_min: int
count_respondent: int
duration: Duration
research_calc_uid: UUID
@dataclass
class Research:
research_name: str
research_cost: float
research_count_respondent: int
research_calc: ResearchCalc
research_uid: UUID = field(default_factory=uuid4)
query = GraphQlQuery(
type_method=GraphQlMethodType.query,
name="GetResearch",
name_method="research",
inputs={"research_uid": UUID("12345678-1234-1234-1234-123456789012")},
models=dataclass_converter.build_graph_ql_models([Research]),
)
print(str(query))
Результат GraphQL:
query GetResearch($research_uid: UUID!) {
research(research_uid: $research_uid) {
research_name
research_cost
research_count_respondent
research_calc {
age_max
age_min
count_respondent
duration {
duration
duration_cost
duration_id
}
research_calc_uid
}
research_uid
}
}
DataConverter - Универсальный конвертер
from graphql_query.converter import DataConverter
# Автоматическое определение типа модели
converter = DataConverter(User, ReturnError, input_data={"user_id": 123})
# Конвертация данных
result = converter(user_data)
variables = converter.variables
models = converter.models
Поддерживаемые преобразования
| Входной тип | Выходной тип | Использование |
|---|---|---|
| Dataclass | Dataclass | DataConverter(DataclassModel) |
| Pydantic | Pydantic | DataConverter(PydanticModel) |
| Dict | Dict | DataConverter(dict_schema) |
| Mixed | TypeError | ❌ Не поддерживается |
Типы данных
Библиотека поддерживает все основные типы GraphQL:
- Скалярные типы:
String,Int,Float,Boolean,ID - Сложные типы: объекты, списки, не-nullable типы
- Специальные типы:
UUID,DateTime(через кастомные скаляры) - Union типы:
Union[TypeA, TypeB] - Optional типы:
Optional[str]→String
Установка
pip install qraphql-alchemy
Тестирование
# Запуск всех тестов
pytest tests/
# Тесты конкретного модуля
pytest tests/test_query.py -v
pytest tests/test_converter.py -v
Особенности
🔄 Мульти-формат
Одинаковая функциональность для dataclasses, Pydantic и словарей
🏗️ Автоматическая генерация
Рекурсивное построение GraphQL схем из сложных моделей
🛡️ Валидация
Проверка совместимости типов и структуры данных
Ограничения
- ❌ Смешивание разных типов моделей в одном конвертере
- ❌ Кастомные директивы GraphQL
- ❌ Фрагменты и inline fragments
- ❌ Подписки (subscriptions)
Совместимость
- Python 3.11+
- GraphQL стандарт
- Совместимо с большинством GraphQL клиентов и серверов
Metadata
Release files for graphql-alchemy 0.0.5
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| graphql_alchemy-0.0.5.tar.gz | 14.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| graphql_alchemy-0.0.5-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 28.1 kB
Release files / graphql_alchemy-0.0.5.tar.gz
| Download URL | graphql_alchemy-0.0.5.tar.gz |
|---|---|
| Size | 14.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
20c2bf4dcb66db681ca250dd61850035d814910868cd6a6222b265245735e612
|
|
BLAKE2b-256 checksum How to use checksums |
ebd96041ba261d82e677be7c1404df4ac90be6c47271cec4bb70ba6057299320
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.11
|
Release files / graphql_alchemy-0.0.5-py3-none-any.whl
| Download URL | graphql_alchemy-0.0.5-py3-none-any.whl |
|---|---|
| Size | 13.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
2ed482a93e16e813a3b293c74cd097fce22ad40b3285e7c7b58cdd272022c4d7
|
|
BLAKE2b-256 checksum How to use checksums |
042f7db3fc5c7754f4f3ca5026d71587aeca975580f2d9532128ee3e038a7e27
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.11
|