GraphQL славится своей гибкостью, так как позволяет запрашивать ровно те данные, которые нужны, и ровно в том формате, в каком они нужны. Именно поэтому в реальных приложениях мы часто сталкиваемся с необходимостью обработать сложные запросы. Так что, если раньше мы строили простые "вопросики" к API вроде "Дай мне список всех пользователей", то теперь переходим к созданию сложных "допросов" вида: "Дай мне список всех пользователей с их заказами, но только за последний месяц, а ещё добавь комментарии к заказам".
Зачем нужны сложные запросы?
Представьте, что у вас есть приложение для интернет-магазина, и вы хотите получить данные об определённом пользователе с его заказами, включая список товаров в каждом заказе. В REST API вам пришлось бы сделать несколько запросов, чтобы собрать всю информацию. GraphQL позволяет сделать это за один запрос! Это упрощает жизнь клиенту (меньше запросов) и делает API более удобным для использования.
Пример запроса:
query {
user(id: 1) {
name
email
orders {
id
total
items {
product {
name
price
}
quantity
}
}
}
}
Этот запрос позволяет вложенно получить данные о пользователе, его заказах и товарах в каждом заказе. Красота, правда?
Основные концепции сложных запросов
Чтобы создавать сложные запросы, нужно понимать несколько ключевых моментов.
- Соединение данных из нескольких моделей
GraphQL легко позволяет извлекать данные из связанных моделей. Например, вы можете получить данные из таблицы пользователей, а затем сразу связать её с таблицей заказов, используя связь ForeignKey в Django. Всё это делается через GraphQL-схему, без необходимости писать дополнительный SQL или изобретать велосипед.
- Обработка больших объемов данных
В реальных приложениях данные могут расти как на дрожжах, и запросы, которые раньше выполнялись за миллисекунды, начинают тормозить сервер. В таких случаях важно понимать, как эффективно формировать сложные запросы, чтобы не перегружать сервер и не возвращать пользователю ненужные данные.
Пример неэффективного запроса:
query {
users {
id
name
orders {
id
items {
id
}
}
}
}
Если у вас 1000 пользователей с тысячами заказов, сервер «захлебнется» от такого запроса. Мы научимся, как этого избежать.
Типы сложных запросов
- Запросы с вложениями (Nested Queries)
GraphQL позволяет запрашивать данные, используя вложенные уровни. Например, вы можете запросить статью и её автора, а также комментарии, написанные к этой статье.
Пример:
query {
article(id: 1) {
title
content
author {
name
email
}
comments {
text
user {
name
}
}
}
}
Этот запрос извлекает данные не только о статье, но и о её авторе, а также о каждом комментарии и комментаторе.
- Запросы с фильтрами
Часто в запросах нужно использовать фильтры, чтобы получать только те данные, которые соответствуют определённым условиям. Например, вы можете запросить заказы, сделанные за прошлую неделю.
Пример:
query {
orders(filter: { date_gte: "2023-01-01", date_lte: "2023-01-07" }) {
id
total
user {
name
}
}
}
Мы передали в запрос аргумент filter, чтобы ограничить выборку.
Примеры сложных запросов
Пример 1: пользователи с их ролями и правами доступа
Допустим, у нас есть модели User, Role и Permission. Один пользователь может иметь несколько ролей, а роль может включать несколько прав.
GraphQL запрос:
query {
users {
id
name
roles {
name
permissions {
name
}
}
}
}
Django модель:
class Permission(models.Model):
name = models.CharField(max_length=100)
class Role(models.Model):
name = models.CharField(max_length=100)
permissions = models.ManyToManyField(Permission)
class User(models.Model):
name = models.CharField(max_length=100)
roles = models.ManyToManyField(Role)
Результат:
{
"data": {
"users": [
{
"id": 1,
"name": "Alice",
"roles": [
{
"name": "Admin",
"permissions": [
{ "name": "Can View" },
{ "name": "Can Edit" }
]
}
]
}
]
}
}
Пример 2: заказы пользователя с товарами
Если у нас есть пользователи, их заказы и товары в заказах, мы можем написать запрос такого вида:
GraphQL запрос:
query {
user(id: 1) {
name
orders {
id
date
items {
product {
name
price
}
quantity
}
}
}
}
Django модель:
class Product(models.Model):
name = models.CharField(max_length=200)
price = models.DecimalField(max_digits=10, decimal_places=2)
class OrderItem(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE)
quantity = models.IntegerField()
class Order(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
items = models.ManyToManyField(OrderItem)
date = models.DateTimeField(auto_now_add=True)
Рекомендации по работе со сложными запросами
Контролируйте вложенность. Не позволяйте клиентам делать запросы с бесконечной вложенностью. Это можно ограничить через настройки GraphQL движка (например,
max_depth).Используйте DataLoader для оптимизации. Это поможет бороться с проблемой N+1 запросов, о которой мы поговорим в следующих лекциях.
Добавляйте фильтры. Ограничьте количество возвращаемых данных, чтобы сервер не обрабатывал миллионы записей.
Используйте директивы. GraphQL позволяет использовать директивы для управления включением или исключением данных.
На этом этапе у вас должно было сформироваться понимание того, зачем вообще нужны сложные запросы, как с ними работать и какие основные подходы существуют. В следующих лекциях мы углубимся в реализацию таких вещей, как вложенные запросы, выборки данных, оптимизация и работа с большими объёмами данных.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ