Graphene – GraphQL на Python

онлайн тренажер по питону
Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Введение в GraphQL и Graphene

GraphQL — это современный язык запросов к API и среда выполнения, разработанные Facebook в 2012 году для решения проблем традиционных REST API. Graphene — это мощная Python-библиотека, предоставляющая полную реализацию GraphQL-спецификации с поддержкой типизированных схем, мутаций и интеграции с популярными ORM-системами.

Что такое GraphQL и зачем он нужен

GraphQL представляет собой декларативный подход к получению данных, где клиент точно описывает, какие данные ему нужны. В отличие от REST, где сервер определяет структуру ответа, GraphQL позволяет клиенту самостоятельно формировать запросы и получать именно те данные, которые требуются.

Ключевые преимущества GraphQL перед REST

Единая точка входа

GraphQL использует один URL-эндпоинт для всех операций, что упрощает архитектуру API и устраняет необходимость версионирования через URL.

Гибкость запросов

Клиент самостоятельно определяет структуру ответа, запрашивая только необходимые поля и связанные данные.

Устранение избыточности данных

Проблемы over-fetching (получение лишних данных) и under-fetching (недостаток данных) решаются на уровне запроса.

Объединение связанных данных

Возможность получить данные из нескольких связанных сущностей в одном запросе, что снижает количество обращений к серверу.

Строгая типизация

Схема GraphQL статически типизирована, что обеспечивает валидацию запросов и автодополнение в IDE.

Автоматическая документация

Схема служит живой документацией API, доступной через интроспекцию.

Установка и настройка Graphene

Базовая установка

pip install graphene

Интеграция с веб-фреймворками

Для Flask:

pip install flask-graphql

Для Django:

pip install graphene-django

Для FastAPI:

pip install starlette-graphene3

Интеграция с базами данных

Для SQLAlchemy:

pip install graphene-sqlalchemy

Для Django ORM:

pip install graphene-django

Создание базового GraphQL-сервера

Пример с Flask

from flask import Flask
from flask_graphql import GraphQLView
import graphene

app = Flask(__name__)

class Query(graphene.ObjectType):
    hello = graphene.String(name=graphene.String(default_value="мир"))
    
    def resolve_hello(self, info, name):
        return f"Привет, {name}!"

schema = graphene.Schema(query=Query)

app.add_url_rule('/graphql', view_func=GraphQLView.as_view(
    'graphql', 
    schema=schema, 
    graphiql=True  # Включает GraphiQL интерфейс
))

if __name__ == '__main__':
    app.run(debug=True)

Пример с Django

# settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'graphene_django',
    'myapp',
]

GRAPHENE = {
    'SCHEMA': 'myproject.schema.schema'
}

# urls.py
from django.urls import path
from graphene_django.views import GraphQLView

urlpatterns = [
    path('graphql/', GraphQLView.as_view(graphiql=True)),
]

Определение типов и схем в Graphene

Создание пользовательских типов

import graphene

class User(graphene.ObjectType):
    id = graphene.ID()
    name = graphene.String()
    email = graphene.String()
    age = graphene.Int()
    is_active = graphene.Boolean()
    
    # Вычисляемые поля
    full_name = graphene.String()
    
    def resolve_full_name(self, info):
        return f"{self.first_name} {self.last_name}"

class Post(graphene.ObjectType):
    id = graphene.ID()
    title = graphene.String()
    content = graphene.String()
    author = graphene.Field(User)
    created_at = graphene.DateTime()

Определение схемы запросов

class Query(graphene.ObjectType):
    user = graphene.Field(User, id=graphene.ID(required=True))
    users = graphene.List(User, limit=graphene.Int(default_value=10))
    
    def resolve_user(self, info, id):
        # Логика получения пользователя по ID
        return User(id=id, name="Иван Петров", email="ivan@example.com")
    
    def resolve_users(self, info, limit):
        # Логика получения списка пользователей
        return [User(id=i, name=f"Пользователь {i}") for i in range(1, limit+1)]

Запросы (Queries): структура и обработка

Простые запросы

{
  user(id: "1") {
    id
    name
    email
  }
}

Запросы с алиасами

{
  firstUser: user(id: "1") {
    name
  }
  secondUser: user(id: "2") {
    name
  }
}

Вложенные запросы

class User(graphene.ObjectType):
    id = graphene.ID()
    name = graphene.String()
    posts = graphene.List(lambda: Post)
    
    def resolve_posts(self, info):
        # Получение постов пользователя
        return [Post(title="Первый пост"), Post(title="Второй пост")]
{
  user(id: "1") {
    name
    posts {
      title
      content
    }
  }
}

Мутации (Mutations): изменение данных

Создание мутации

class CreateUser(graphene.Mutation):
    class Arguments:
        name = graphene.String(required=True)
        email = graphene.String(required=True)
    
    # Поля возвращаемого результата
    ok = graphene.Boolean()
    user = graphene.Field(User)
    errors = graphene.List(graphene.String)
    
    def mutate(self, info, name, email):
        # Валидация
        if not email or '@' not in email:
            return CreateUser(ok=False, errors=["Некорректный email"])
        
        # Создание пользователя
        user = User(name=name, email=email)
        return CreateUser(ok=True, user=user)

class UpdateUser(graphene.Mutation):
    class Arguments:
        id = graphene.ID(required=True)
        name = graphene.String()
        email = graphene.String()
    
    user = graphene.Field(User)
    
    def mutate(self, info, id, name=None, email=None):
        # Логика обновления пользователя
        user = User(id=id, name=name, email=email)
        return UpdateUser(user=user)

class Mutation(graphene.ObjectType):
    create_user = CreateUser.Field()
    update_user = UpdateUser.Field()

Выполнение мутации

mutation {
  createUser(name: "Иван Петров", email: "ivan@example.com") {
    ok
    user {
      id
      name
      email
    }
    errors
  }
}

Работа с аргументами в запросах и мутациях

Типы аргументов

class Query(graphene.ObjectType):
    users = graphene.List(
        User,
        first=graphene.Int(default_value=10),
        skip=graphene.Int(default_value=0),
        search=graphene.String(),
        is_active=graphene.Boolean(default_value=True)
    )
    
    def resolve_users(self, info, first, skip, search=None, is_active=True):
        # Логика фильтрации и пагинации
        users = []  # Получение из базы данных
        
        if search:
            users = [u for u in users if search.lower() in u.name.lower()]
        
        if is_active is not None:
            users = [u for u in users if u.is_active == is_active]
        
        return users[skip:skip+first]

Использование InputObjectType

class UserInput(graphene.InputObjectType):
    name = graphene.String(required=True)
    email = graphene.String(required=True)
    age = graphene.Int()

class CreateUserWithInput(graphene.Mutation):
    class Arguments:
        user_data = UserInput(required=True)
    
    user = graphene.Field(User)
    
    def mutate(self, info, user_data):
        user = User(**user_data)
        return CreateUserWithInput(user=user)

Резолверы (resolvers): логика обработки данных

Стандартные резолверы

class User(graphene.ObjectType):
    id = graphene.ID()
    name = graphene.String()
    email = graphene.String()
    posts_count = graphene.Int()
    
    def resolve_posts_count(self, info):
        # Подсчет количества постов пользователя
        return len(getattr(self, 'posts', []))
    
    def resolve_email(self, info):
        # Проверка прав доступа
        user = info.context.get('user')
        if user and user.id == self.id:
            return self.email
        return None  # Скрыть email для других пользователей

Асинхронные резолверы

import asyncio

class Query(graphene.ObjectType):
    user = graphene.Field(User, id=graphene.ID())
    
    async def resolve_user(self, info, id):
        # Асинхронное получение данных
        await asyncio.sleep(0.1)  # Имитация запроса к базе данных
        return User(id=id, name="Асинхронный пользователь")

Подключение к базе данных

Интеграция с SQLAlchemy

from sqlalchemy import create_engine, Column, Integer, String, DateTime
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from graphene_sqlalchemy import SQLAlchemyObjectType

Base = declarative_base()

class UserModel(Base):
    __tablename__ = 'users'
    
    id = Column(Integer, primary_key=True)
    name = Column(String)
    email = Column(String)
    created_at = Column(DateTime)

class User(SQLAlchemyObjectType):
    class Meta:
        model = UserModel
        interfaces = (graphene.relay.Node,)

class Query(graphene.ObjectType):
    users = graphene.List(User)
    
    def resolve_users(self, info):
        query = User.get_query(info)
        return query.all()

Интеграция с Django ORM

from django.db import models
from graphene_django import DjangoObjectType

class UserModel(models.Model):
    name = models.CharField(max_length=100)
    email = models.EmailField()
    created_at = models.DateTimeField(auto_now_add=True)

class User(DjangoObjectType):
    class Meta:
        model = UserModel
        fields = ("id", "name", "email", "created_at")
    
    posts_count = graphene.Int()
    
    def resolve_posts_count(self, info):
        return self.posts.count()

Работа с вложенными объектами и связями

Определение связей

class Post(graphene.ObjectType):
    id = graphene.ID()
    title = graphene.String()
    content = graphene.String()
    author = graphene.Field(lambda: User)
    tags = graphene.List(lambda: Tag)
    
    def resolve_author(self, info):
        return User(id=self.author_id, name="Автор поста")
    
    def resolve_tags(self, info):
        return [Tag(name="Python"), Tag(name="GraphQL")]

class User(graphene.ObjectType):
    id = graphene.ID()
    name = graphene.String()
    posts = graphene.List(Post)
    
    def resolve_posts(self, info):
        return [Post(id=1, title="Первый пост", author_id=self.id)]

Решение проблемы N+1 запросов

from promise import Promise
from promise.dataloader import DataLoader

class UserLoader(DataLoader):
    def batch_load_fn(self, user_ids):
        # Загрузка всех пользователей одним запросом
        users = UserModel.objects.filter(id__in=user_ids)
        user_map = {user.id: user for user in users}
        return Promise.resolve([user_map.get(user_id) for user_id in user_ids])

class Post(graphene.ObjectType):
    author = graphene.Field(User)
    
    def resolve_author(self, info):
        return info.context['user_loader'].load(self.author_id)

Использование Graphene-Django

Настройка проекта

# settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'graphene_django',
    'myapp',
]

GRAPHENE = {
    'SCHEMA': 'myproject.schema.schema',
    'MIDDLEWARE': [
        'graphene_django.debug.DjangoDebugMiddleware',
    ],
}

Создание схемы

# schema.py
import graphene
from graphene_django import DjangoObjectType
from .models import User, Post

class UserType(DjangoObjectType):
    class Meta:
        model = User
        fields = "__all__"

class PostType(DjangoObjectType):
    class Meta:
        model = Post
        fields = "__all__"

class Query(graphene.ObjectType):
    users = graphene.List(UserType)
    posts = graphene.List(PostType)
    
    def resolve_users(self, info):
        return User.objects.all()
    
    def resolve_posts(self, info):
        return Post.objects.select_related('author').all()

schema = graphene.Schema(query=Query)

Интеграция с Flask и FastAPI

Flask с GraphQL

from flask import Flask, request, jsonify
from flask_graphql import GraphQLView
import graphene

app = Flask(__name__)

class Query(graphene.ObjectType):
    hello = graphene.String()
    
    def resolve_hello(self, info):
        user = info.context.get('user')
        return f"Привет, {user.name if user else 'гость'}!"

schema = graphene.Schema(query=Query)

def get_context():
    return {'user': getattr(request, 'user', None)}

app.add_url_rule('/graphql', view_func=GraphQLView.as_view(
    'graphql',
    schema=schema,
    graphiql=True,
    get_context=get_context
))

FastAPI с GraphQL

from fastapi import FastAPI
from starlette_graphene3 import GraphQLApp
import graphene

app = FastAPI()

class Query(graphene.ObjectType):
    hello = graphene.String()
    
    def resolve_hello(self, info):
        return "Привет из FastAPI!"

schema = graphene.Schema(query=Query)

app.mount("/graphql", GraphQLApp(schema=schema))

Авторизация и аутентификация

Передача контекста

from flask import g
from functools import wraps

def login_required(f):
    @wraps(f)
    def decorated_function(*args, **kwargs):
        if not g.user:
            raise Exception("Требуется авторизация")
        return f(*args, **kwargs)
    return decorated_function

class Query(graphene.ObjectType):
    my_profile = graphene.Field(User)
    
    @login_required
    def resolve_my_profile(self, info):
        user = info.context.get('user')
        return User(id=user.id, name=user.name)

Права доступа на уровне полей

class User(graphene.ObjectType):
    id = graphene.ID()
    name = graphene.String()
    email = graphene.String()
    
    def resolve_email(self, info):
        current_user = info.context.get('user')
        if current_user and (current_user.id == self.id or current_user.is_admin):
            return self.email
        return None

Обработка ошибок и валидация

Пользовательские исключения

class ValidationError(Exception):
    def __init__(self, message, field=None):
        self.message = message
        self.field = field
        super().__init__(self.message)

class CreateUser(graphene.Mutation):
    class Arguments:
        name = graphene.String(required=True)
        email = graphene.String(required=True)
    
    user = graphene.Field(User)
    errors = graphene.List(graphene.String)
    
    def mutate(self, info, name, email):
        errors = []
        
        if len(name) < 2:
            errors.append("Имя должно содержать минимум 2 символа")
        
        if '@' not in email:
            errors.append("Некорректный формат email")
        
        if errors:
            return CreateUser(errors=errors)
        
        try:
            # Создание пользователя
            user = User(name=name, email=email)
            return CreateUser(user=user)
        except Exception as e:
            return CreateUser(errors=[str(e)])

Глобальная обработка ошибок

class CustomMiddleware:
    def resolve(self, next, root, info, **args):
        try:
            return next(root, info, **args)
        except ValidationError as e:
            return {"error": e.message, "field": e.field}
        except Exception as e:
            return {"error": "Внутренняя ошибка сервера"}

Тестирование GraphQL API

Тестирование с pytest

import pytest
import json
from graphene.test import Client

def test_user_query():
    client = Client(schema)
    
    query = '''
    {
        user(id: "1") {
            id
            name
        }
    }
    '''
    
    result = client.execute(query)
    assert result['data']['user']['id'] == "1"
    assert result['data']['user']['name'] == "Тестовый пользователь"

def test_create_user_mutation():
    client = Client(schema)
    
    mutation = '''
    mutation {
        createUser(name: "Новый пользователь", email: "test@example.com") {
            ok
            user {
                name
                email
            }
        }
    }
    '''
    
    result = client.execute(mutation)
    assert result['data']['createUser']['ok'] == True
    assert result['data']['createUser']['user']['name'] == "Новый пользователь"

Тестирование с Flask

import pytest
from flask import Flask
from flask_graphql import GraphQLView

@pytest.fixture
def app():
    app = Flask(__name__)
    app.add_url_rule('/graphql', view_func=GraphQLView.as_view('graphql', schema=schema))
    return app

def test_graphql_endpoint(app):
    client = app.test_client()
    
    query = {
        "query": "{ user(id: \"1\") { name } }"
    }
    
    response = client.post('/graphql', 
                          data=json.dumps(query),
                          content_type='application/json')
    
    assert response.status_code == 200
    data = json.loads(response.data)
    assert 'data' in data

Производительность и оптимизация

Пагинация

class Query(graphene.ObjectType):
    users = graphene.List(
        User,
        first=graphene.Int(default_value=10),
        skip=graphene.Int(default_value=0)
    )
    
    def resolve_users(self, info, first, skip):
        return User.objects.all()[skip:skip+first]

Relay-совместимая пагинация

from graphene import relay

class User(graphene.ObjectType):
    class Meta:
        interfaces = (relay.Node,)
    
    id = graphene.ID()
    name = graphene.String()

class Query(graphene.ObjectType):
    users = relay.ConnectionField(User)
    
    def resolve_users(self, info, **args):
        return User.objects.all()

Кэширование

from functools import lru_cache

class Query(graphene.ObjectType):
    users = graphene.List(User)
    
    @lru_cache(maxsize=128)
    def resolve_users(self, info):
        return User.objects.all()

Инструменты и IDE для работы с GraphQL

GraphiQL

Встроенный интерфейс для тестирования запросов:

# Flask
GraphQLView.as_view('graphql', schema=schema, graphiql=True)

# Django
GraphQLView.as_view(graphiql=True)

Дополнительные инструменты

  • GraphQL Playground - современная альтернатива GraphiQL
  • Postman - поддержка GraphQL запросов
  • Insomnia - специализированный REST/GraphQL клиент
  • Apollo Client DevTools - расширение для браузера
  • VSCode GraphQL - расширения для автодополнения и подсветки синтаксиса

Примеры практического применения

Единый API для разных клиентов

class Query(graphene.ObjectType):
    # Полная информация для веб-клиента
    user_detailed = graphene.Field(User, id=graphene.ID())
    
    # Краткая информация для мобильного приложения
    user_mobile = graphene.Field(User, id=graphene.ID())
    
    def resolve_user_detailed(self, info, id):
        return User.objects.select_related('profile', 'settings').get(id=id)
    
    def resolve_user_mobile(self, info, id):
        return User.objects.only('id', 'name', 'avatar').get(id=id)

Агрегация данных из разных источников

class Query(graphene.ObjectType):
    dashboard = graphene.Field(DashboardType, user_id=graphene.ID())
    
    def resolve_dashboard(self, info, user_id):
        # Данные из базы данных
        user = User.objects.get(id=user_id)
        
        # Данные из внешнего API
        external_data = fetch_external_data(user_id)
        
        # Данные из кэша
        cached_stats = get_cached_stats(user_id)
        
        return DashboardType(
            user=user,
            external_info=external_data,
            statistics=cached_stats
        )

Полное описание библиотеки Graphene

Основные модули и компоненты

Модуль Описание
graphene.ObjectType Базовый класс для создания GraphQL объектов
graphene.Schema Главная схема, объединяющая запросы, мутации и подписки
graphene.Field Определение поля в объекте
graphene.List Список объектов определенного типа
graphene.NonNull Поле, которое не может быть null
graphene.Mutation Базовый класс для мутаций
graphene.InputObjectType Тип для входных данных
graphene.Interface Интерфейс для общих полей
graphene.Union Объединение нескольких типов
graphene.Enum Перечисление возможных значений

Скалярные типы

Тип Описание Python тип
graphene.String Строка str
graphene.Int Целое число int
graphene.Float Число с плавающей точкой float
graphene.Boolean Логический тип bool
graphene.ID Уникальный идентификатор str
graphene.Date Дата datetime.date
graphene.DateTime Дата и время datetime.datetime
graphene.Time Время datetime.time
graphene.Decimal Десятичное число decimal.Decimal
graphene.JSONString JSON строка dict

Декораторы и утилиты

Декоратор/Утилита Описание
@staticmethod Статический резолвер
@classmethod Классовый резолвер
graphene.resolve_only_args Упрощенный декоратор для резолверов
graphene.Context Контекст выполнения запроса
graphene.ResolveInfo Информация о текущем запросе

Методы Schema

Метод Описание
schema.execute(query, context=None, variables=None) Выполнение GraphQL запроса
schema.execute_async(query, context=None, variables=None) Асинхронное выполнение запроса
schema.get_type(name) Получение типа по имени
schema.get_graphql_type(name) Получение GraphQL типа

Интеграционные пакеты

Пакет Описание
graphene-django Интеграция с Django
graphene-sqlalchemy Интеграция с SQLAlchemy
graphene-mongo Интеграция с MongoDB
flask-graphql Интеграция с Flask
starlette-graphene3 Интеграция с FastAPI/Starlette

Часто задаваемые вопросы

Что такое Graphene и чем он отличается от других GraphQL библиотек?

Graphene — это наиболее зрелая и функциональная библиотека для создания GraphQL API на Python. Она отличается декларативным подходом к определению схем, обширной экосистемой интеграций и активным сообществом разработчиков.

Как Graphene решает проблему N+1 запросов?

Graphene поддерживает DataLoader паттерн для батчинга запросов, а также интеграцию с ORM для оптимизации запросов к базе данных через select_related() и prefetch_related() в Django или eager loading в SQLAlchemy.

Можно ли использовать Graphene с асинхронными фреймворками?

Да, Graphene поддерживает асинхронные резолверы и может работать с FastAPI, Starlette и другими асинхронными фреймворками через соответствующие интеграции.

Как обеспечить безопасность GraphQL API?

Рекомендуется использовать ограничения глубины запросов, таймауты, валидацию входных данных, аутентификацию на уровне резолверов и анализ сложности запросов для предотвращения DoS-атак.

Поддерживает ли Graphene GraphQL подписки?

Да, Graphene поддерживает подписки через graphene.ObjectType с использованием WebSocket или Server-Sent Events для real-time обновлений.

Как тестировать GraphQL API, созданный с помощью Graphene?

Graphene предоставляет встроенный тестовый клиент graphene.test.Client, который позволяет выполнять запросы без HTTP-сервера. Также можно использовать стандартные тестовые инструменты фреймворков.

Можно ли использовать Graphene для создания микросервисной архитектуры?

Да, Graphene подходит для микросервисов. Можно создать GraphQL Gateway, который агрегирует данные из разных сервисов, или использовать GraphQL Federation для объединения схем.

Как мигрировать с REST API на GraphQL с использованием Graphene?

Миграция может быть постепенной: сначала создать GraphQL эндпоинты параллельно с REST, затем постепенно переводить клиентов на GraphQL. Graphene позволяет легко обернуть существующую бизнес-логику в GraphQL резолверы.

Полный справочник методов и функций Graphene

Категория Компонент/Метод Описание Пример использования
Основные классы graphene.ObjectType Базовый класс для GraphQL объектов class User(graphene.ObjectType): pass
  graphene.Schema Главная схема API schema = graphene.Schema(query=Query)
  graphene.Field Определение поля name = graphene.Field(graphene.String)
  graphene.List Список объектов users = graphene.List(User)
  graphene.NonNull Обязательное поле id = graphene.NonNull(graphene.ID)
Скалярные типы graphene.String Строковый тип name = graphene.String()
  graphene.Int Целочисленный тип age = graphene.Int()
  graphene.Float Число с плавающей точкой price = graphene.Float()
  graphene.Boolean Логический тип is_active = graphene.Boolean()
  graphene.ID Уникальный идентификатор id = graphene.ID()
  graphene.Date Дата birth_date = graphene.Date()
  graphene.DateTime Дата и время created_at = graphene.DateTime()
  graphene.JSONString JSON строка metadata = graphene.JSONString()
Мутации graphene.Mutation Базовый класс мутаций class CreateUser(graphene.Mutation): pass
  Arguments Аргументы мутации class Arguments: name = graphene.String()
  mutate() Метод выполнения мутации def mutate(self, info, **args): pass
Входные типы graphene.InputObjectType Тип для входных данных class UserInput(graphene.InputObjectType): pass
  graphene.Argument Аргумент поля user = graphene.Field(User, id=graphene.Argument(graphene.ID))
Интерфейсы и объединения graphene.Interface Интерфейс class Node(graphene.Interface): pass
  graphene.Union Объединение типов class SearchResult(graphene.Union): pass
  graphene.Enum Перечисление class Status(graphene.Enum): ACTIVE = 1
Резолверы resolve_<field>() Резолвер поля def resolve_name(self, info): return self.name
  info.context Контекст запроса user = info.context.get('user')
  info.field_name Имя текущего поля field = info.field_name
  info.parent_type Родительский тип parent = info.parent_type
Выполнение запросов schema.execute() Синхронное выполнение result = schema.execute(query)
  schema.execute_async() Асинхронное выполнение result = await schema.execute_async(query)
Relay graphene.relay.Node Relay Node интерфейс class User(graphene.ObjectType): class Meta: interfaces = (graphene.relay.Node,)
  graphene.relay.Connection Relay Connection users = graphene.relay.ConnectionField(User)
  graphene.relay.ClientIDMutation Relay мутация class CreateUser(graphene.relay.ClientIDMutation): pass
Подписки graphene.ObjectType Подписки class Subscription(graphene.ObjectType): pass
Middleware Middleware classes Промежуточное ПО class AuthMiddleware: def resolve(self, next, root, info, **args): pass
Утилиты graphene.is_type() Проверка типа if graphene.is_type(obj, User): pass
  graphene.get_type() Получение типа user_type = graphene.get_type(User)
Валидация Custom validators Пользовательская валидация def validate_email(email): return '@' in email
Кэширование Field-level caching Кэширование на уровне полей @lru_cache(maxsize=128)
Батчинг DataLoader pattern Батчинг запросов user_loader = DataLoader(batch_load_users)
Интроспекция Schema introspection Интроспекция схемы schema.get_type_map()
Отладка Debug middleware Отладочное ПО DjangoDebugMiddleware

Graphene предоставляет мощный и гибкий инструментарий для создания современных GraphQL API на Python, поддерживая все основные возможности GraphQL спецификации и предоставляя удобные интеграции с популярными веб-фреймворками и ORM-системами.

 

Новости