JavaRush /Курси /Модуль 5. Spring /Лекція 285: Робота з мутаціями (Mutations)

Лекція 285: Робота з мутаціями (Mutations)

Модуль 5. Spring
Рівень 15 , Лекція 4
Відкрита

Якщо query — це спосіб отримувати дані, то mutation — це спосіб змінювати дані на сервері. Аналогічно методам POST, PUT або DELETE в REST, мутації дозволяють додавати, оновлювати або видаляти дані.

Основні відмінності мутацій від запитів (queries)

  • Семантика дії: мутації призначені для модифікації стану сервера.
  • Розташування в схемі: мутації визначаються окремим блоком mutation в схемі GraphQL.
  • Тип відповіді: як і запити, мутації повертають дані. Однак повернуті дані часто містять результат виконаної зміни (наприклад, оновлений об'єкт).

Основи роботи з мутаціями

Для початку визначимо, як мутації виглядають у GraphQL. Розглянемо приклад:

Приклад: створення нового користувача

Схема GraphQL:


type Mutation {
    createUser(input: CreateUserInput): User
}

input CreateUserInput {
    name: String!
    email: String!
}

type User {
    id: ID!
    name: String!
    email: String!
}

Тут:

  • Mutation описує операцію зміни даних.
  • Input використовується для передачі аргументів в createUser. Це зручно, бо дозволяє групувати параметри.
  • User представляє тип повернутого об'єкта.

Запит мутації:


mutation {
    createUser(input: { name: "Сергій", email: "sergey@example.com" }) {
        id
        name
        email
    }
}

Відповідь сервера:


{
  "data": {
    "createUser": {
      "id": "1",
      "name": "Сергій",
      "email": "sergey@example.com"
    }
  }
}

Реалізація мутацій у Spring Boot

Тепер давайте реалізуємо createUser у вашому Spring Boot додатку.

Крок 1: Визначення схеми

Створіть файл schema.graphqls в папці src/main/resources/graphql. Додайте таку схему:


type Mutation {
    createUser(input: CreateUserInput): User
}

input CreateUserInput {
    name: String!
    email: String!
}

type User {
    id: ID!
    name: String!
    email: String!
}

Ця схема описує вхідні дані (CreateUserInput) і повернений об'єкт (User).

Крок 2: Створення моделі даних

Створіть клас User для представлення сутності користувача:


package com.example.graphql.model;

public class User {
    private String id;
    private String name;
    private String email;

    // Конструктори
    public User() {}

    public User(String id, String name, String email) {
        this.id = id;
        this.name = name;
        this.email = email;
    }

    // Геттери та сеттери
    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }
}

Крок 3: Реалізація резолвера мутацій

Створіть клас резолвера:


package com.example.graphql.resolver;

import com.example.graphql.model.User;
import org.springframework.stereotype.Component;
import java.util.UUID;

@Component
public class MutationResolver {

    public User createUser(String name, String email) {
        // Створюємо нового користувача (у реальному додатку дані зберігалися б у базі даних)
        return new User(UUID.randomUUID().toString(), name, email);
    }
}

Цей резолвер створює нового користувача і повертає його. Для генерації унікального id ми використовуємо UUID.

Крок 4: Зв'язування схеми та резолвера

Зв'яжемо схему з резолвером за допомогою GraphQLMutationResolver:


package com.example.graphql.resolver;

import com.example.graphql.model.User;
import graphql.kickstart.tools.GraphQLMutationResolver;
import org.springframework.stereotype.Component;

@Component
public class UserMutationResolver implements GraphQLMutationResolver {

    public User createUser(String name, String email) {
        // Логіка створення користувача в резолвері
        return new User(UUID.randomUUID().toString(), name, email);
    }
}

Тут:

  • Ми реалізуємо інтерфейс GraphQLMutationResolver, який автоматично зв'язує мутації з GraphQL.

Крок 5: Тестування мутацій

Запустіть додаток і відкрийте GraphQL Playground (або інший інструмент, наприклад Insomnia). Виконайте наступний запит:


mutation {
    createUser(input: { name: "Анна", email: "anna@example.com" }) {
        id
        name
        email
    }
}

Очікувана відповідь:


{
  "data": {
    "createUser": {
      "id": "cd3f7628-1137-45a4-85ba-ecfc988b0278",
      "name": "Анна",
      "email": "anna@example.com"
    }
  }
}

Обробка помилок та валідація

Коли йдеться про мутації, важливо подбати про дві речі:

  1. Валідація вхідних даних.
  2. Обробка помилок.

Для валідації даних ми можемо використати бібліотеку javax.validation. Наприклад:

Крок 1: Додайте анотації в Input-клас


import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;

public class CreateUserInput {

    @NotBlank(message = "Ім'я не може бути порожнім")
    private String name;

    @Email(message = "Некоректний формат email")
    private String email;

    // Геттери та сеттери...
}

Крок 2: Увімкніть валідацію в резолвері


import javax.validation.Valid;

@Component
public class UserMutationResolver implements GraphQLMutationResolver {

    public User createUser(@Valid CreateUserInput input) {
        return new User(UUID.randomUUID().toString(), input.getName(), input.getEmail());
    }
}

При некоректних даних сервер поверне відповідь з повідомленням про помилку.

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


{
  "errors": [
    {
      "message": "Ім'я не може бути порожнім",
      "locations": [...],
      "path": [...]
    }
  ]
}

Підсумкові поради

  1. Мутації схожі на POST/PUT у REST: якщо ви вже писали REST-контролери, робота з мутаціями здасться інтуїтивно зрозумілою.
  2. Не забувайте про валідацію: вона позбавить вас головного болю при обробці вхідних даних.
  3. Обробляйте помилки грамотно: повертайте клієнту зрозумілі повідомлення, щоб їм не довелося звертатися до вашого Slack'у!

У наступній лекції ми заглибимося в роботу з Data Fetchers, які допоможуть зробити наші запити ще гнучкішими!

Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ