JavaRush /Курси /Модуль 3: Django /Написання запитів (queries) і мутацій (mutations)

Написання запитів (queries) і мутацій (mutations)

Модуль 3: Django
Рівень 24 , Лекція 4
Відкрита

Продовжуємо вивчати GraphQL. Сьогодні ми розберемо, як створювати запити (queries) для отримання даних

і мутації (mutations) для зміни даних. Починаємо!

Основи роботи з Query у GraphQL

Query — це спосіб запитувати дані від API. Головна особливість GraphQL у тому, що клієнт сам визначає структуру відповіді. Це трохи схоже на похід у ресторан, де ви не замовляєте "суп", а кажете: "Мені, будь ласка, суп, але тільки без моркви і побільше картоплі".

Почнемо з простого прикладу запиту, наприклад, списку користувачів. Припустимо, у нас вже є модель користувача:

# models.py
from django.db import models

class User(models.Model):
    name = models.CharField(max_length=100)
    email = models.EmailField(unique=True)

Тепер створимо GraphQL-схему для отримання даних про користувачів:

# schema.py
import graphene
from graphene_django.types import DjangoObjectType
from .models import User

class UserType(DjangoObjectType):
    class Meta:
        model = User

class Query(graphene.ObjectType):
    all_users = graphene.List(UserType)

    def resolve_all_users(root, info):
        return User.objects.all()

schema = graphene.Schema(query=Query)
  1. DjangoObjectType — це спеціальний тип, який дозволяє автоматично зв'язати нашу модель Django з GraphQL.
  2. all_users — опис запиту: він поверне список усіх користувачів.
  3. resolve_all_users — функція, яка виконує запит до бази даних і повертає дані.

Тепер ми можемо протестувати це у GraphiQL або іншому інструменті:

query {
    allUsers {
        name
        email
    }
}

У відповіді ми отримаємо:

{
  "data": {
    "allUsers": [
      {
        "name": "Alice",
        "email": "alice@example.com"
      },
      {
        "name": "Bob",
        "email": "bob@example.com"
      }
    ]
  }
}

Динамічні запити: робота з параметрами

Іноді нам потрібні дані не про всіх користувачів, а про конкретного. Додамо можливість шукати користувача за ID:

class Query(graphene.ObjectType):
    user_by_id = graphene.Field(UserType, id=graphene.Int(required=True))

    def resolve_user_by_id(root, info, id):
        return User.objects.get(pk=id)

Тепер запит може виглядати так:

query {
    userById(id: 1) {
        name
        email
    }
}

А відповідь:

{
  "data": {
    "userById": {
      "name": "Alice",
      "email": "alice@example.com"
    }
  }
}
⚠️ Типова помилка:

звернення до неіснуючого ID призведе до виключення DoesNotExist. Цей сценарій можна обробити, повертаючи None або викидаючи зрозуміле клієнту виключення.

Основи роботи з Mutation у GraphQL

Mutation (мутація) — це спосіб змінювати дані (додавати, оновлювати або видаляти). Концептуально це схоже на HTTP POST/PUT/DELETE запити в REST, але працює гнучкіше та централізовано.

Наведемо приклад базової мутації. Додамо можливість створювати користувача через GraphQL:

class CreateUser(graphene.Mutation):
    class Arguments:
        name = graphene.String(required=True)
        email = graphene.String(required=True)

    user = graphene.Field(UserType)

    def mutate(root, info, name, email):
        user = User(name=name, email=email)
        user.save()
        return CreateUser(user=user)

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

Як це працює:

  1. Arguments — описує вхідні параметри для мутації.
  2. mutate — функція, що виконує логіку створення. Вона отримує параметри, створює об'єкт і повертає його.
  3. user — результат, який повернеться клієнту.

Тепер тестуємо мутацію:

mutation {
    createUser(name: "Charlie", email: "charlie@example.com") {
        user {
            name
            email
        }
    }
}

У відповіді ми отримуємо:

{
  "data": {
    "createUser": {
      "user": {
        "name": "Charlie",
        "email": "charlie@example.com"
      }
    }
  }
}

І запис з'являється в базі даних. Успіх!

Оновлення даних за допомогою Mutation

Окей, користувач створив свій акаунт із помилкою в імені. Давайте додамо функцію для оновлення імені користувача:

class UpdateUser(graphene.Mutation):
    class Arguments:
        id = graphene.Int(required=True)
        name = graphene.String(required=True)

    user = graphene.Field(UserType)

    def mutate(root, info, id, name):
        user = User.objects.get(pk=id)
        user.name = name
        user.save()
        return UpdateUser(user=user)

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

Запит для оновлення:

mutation {
    updateUser(id: 1, name: "Alice Updated") {
        user {
            name
        }
    }
}

І у відповіді бачимо:

{
  "data": {
    "updateUser": {
      "user": {
        "name": "Alice Updated"
      }
    }
  }
}
⚠️ Типова помилка:

запит до неіснуючого ID також може викинути виняток, тому додавання перевірки з повідомленням про помилку — гарна практика.

Видалення даних за допомогою Mutation

Додамо функцію видалення користувача:

class DeleteUser(graphene.Mutation):
    class Arguments:
        id = graphene.Int(required=True)

    ok = graphene.Boolean()

    def mutate(root, info, id):
        try:
            user = User.objects.get(pk=id)
            user.delete()
            return DeleteUser(ok=True)
        except User.DoesNotExist:
            return DeleteUser(ok=False)

class Mutation(graphene.ObjectType):
    delete_user = DeleteUser.Field()

Тепер запит для видалення:

mutation {
    deleteUser(id: 1) {
        ok
    }
}

Відповідь, якщо ID існує:

{
  "data": {
    "deleteUser": {
      "ok": true
    }
  }
}

Тестування запитів і мутацій

Не забувай тестувати свої запити і мутації через GraphiQL або GraphQL Playground. Переконайся, що запити працюють передбачувано, а помилки повертаються в зрозумілому форматі клієнту.

Приклад помилок:

  1. Відсутність обов'язкового параметра: GraphQL повертає помилку про відсутній аргумент.
  2. Некоректний параметр: переконайся, що введені значення проходять валідацію, наприклад, email перевіряється на коректність.

Оптимізація запитів

Для підвищення швидкості, особливо при роботі з великими обсягами даних, використовуйте Django QuerySet методи select_related і prefetch_related, щоб мінімізувати кількість запитів до бази даних.

Приклад з select_related:

def resolve_all_users(root, info):
    return User.objects.select_related("profile").all()

GraphQL дає можливість об'єднати запити та мутації в єдиний, потужний інструмент взаємодії між клієнтом і сервером. При правильному налаштуванні ви зможете досягти гнучкості та ефективності, про яку REST тільки мріє. Вперед до наступної лекції! 😉

3
Опитування
Вступ до GraphQL із Django, рівень 24, лекція 4
Недоступний
Вступ до GraphQL із Django
Вступ до GraphQL із Django
Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ