Короткий ответ
GraphQL позволяет клиенту одним запросом запросить произвольный набор полей и связанных сущностей через единый эндпоинт, в отличие от REST с фиксированной формой ответа на фиксированном URL; при этом резолверы для вложенных полей часто вызываются отдельно для каждого элемента списка, что создаёт классический N+1 на уровне резолверов, если не использовать batching (например, DataLoader).
Как это работает подробнее
в REST сервер решает, какие данные вернуть на конкретный путь; в GraphQL клиент описывает нужную форму ответа в запросе (query), а сервер исполняет граф резолверов, где каждое поле может иметь собственную функцию получения данных, независимо вызываемую для каждого родительского объекта.
Пример кода
example.py
# Псевдокод резолвера на Python (Graphene/Strawberry-подобный стиль)
# Намеренная проблема N+1: отдельный запрос на автора для каждого поста
def resolve_author(post, info):
return db.query(Author).get(post.author_id) # вызывается отдельно для каждого post в списке
# Исправление через batching (DataLoader-подобный паттерн)
def resolve_author_batched(post, info):
return info.context["author_loader"].load(post.author_id) # накапливает ID и делает один IN-запросЧто использовать на практике
- Рекомендация. GraphQL решает проблему "недостаточности данных за один запрос" (undersetching) и "избыточности данных" (overfetching), характерные для жёстких REST-ответов, но добавляет сложность на стороне сервера: без батчинга резолвер для поля
authorу списка из 50 постов выполнит 50 отдельных запросов к БД. Выбор между REST и GraphQL зависит от разнообразия клиентов и их потребностей в данных, а не является универсально "более современным" решением.
Подводные камни
- Риски. внедрять GraphQL, рассчитывая, что он "сам" решит проблемы производительности REST, и не предусматривать batching резолверов с самого начала; не ограничивать глубину/сложность запроса на стороне сервера, что позволяет клиенту сформировать чрезмерно дорогой вложенный запрос (query complexity attack).