JavaRush /Курсы /Модуль 5. Spring /Лекция 290: Подписки (Subscriptions) в GraphQL

Лекция 290: Подписки (Subscriptions) в GraphQL

Модуль 5. Spring
29 уровень , 9 лекция
Открыта

Подписки в GraphQL (от англ. Subscriptions) — это механизм получения данных от сервера в реальном времени, без необходимости повторно отправлять запросы. Если совсем просто, подписки позволяют пользователям "подключиться" к определённым событиям или изменениям данных, чтобы получать уведомления об этом сразу после их возникновения.

Подписки делают ваше приложение более динамичным и интерактивным. Представьте себе:

  • Чат-приложение, которое обновляет сообщения в реальном времени, без необходимости рефреша страницы.
  • Онлайн-аукцион, где пользователи моментально видят новые ставки.
  • Спортивный стриминг, который в прямом эфире обновляет счёт матча.

Подписки заменяют "громоздкие" механизмы вроде периодической отправки запросов (polling) или долгоживущих HTTP-соединений.


Как устроены подписки в GraphQL?

Подписки используют WebSocket для установления постоянного соединения между клиентом и сервером. Когда клиент подписывается на определённое событие, сервер поддерживает открытый канал и отправляет обновления по мере их появления. Это как подписка на рассылку новостей — вы один раз подписываетесь, а дальше получаете уведомления.

Пример подписки на новое сообщение в чате на языке GraphQL:


subscription OnNewMessage {
  newMessage(chatId: "123") {
    id
    content
    sender {
      name
    }
    timestamp
  }
}

Компоненты подписок

  1. Схема GraphQL: задаёт типы данных, которые будут возвращаться по подписке.
  2. Event Publisher: механизм для генерации событий на сервере (Spring Boot использует Project Reactor для реактивных потоков).
  3. WebSocket-транспорт: обеспечивает двустороннюю связь клиента и сервера.

Реализация подписок в Spring GraphQL

Давайте вместе настроим подписки для вашего Spring Boot приложения с GraphQL.

1. Настройка зависимостей

Для работы с подписками нужно добавить зависимости в pom.xml. Не забудьте подключить GraphQL WebSocket-транспорт!


<dependency>
    <groupId>com.graphql-java-kickstart</groupId>
    <artifactId>graphql-spring-boot-starter</artifactId>
    <version>11.1.0</version>
</dependency>
<dependency>
    <groupId>com.graphql-java-kickstart</groupId>
    <artifactId>graphql-java-tools</artifactId>
    <version>11.1.0</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-websocket</artifactId>
</dependency>

После добавления зависимостей помните про магическую команду mvn clean install, чтобы Maven подтянул всё необходимое.

2. Создание схемы подписки

Создадим файл schema.graphqls и опишем нашу подписку.


type Subscription {
  messageAdded: Message
}

type Message {
  id: ID
  text: String
  sender: String
  timestamp: String
}

Здесь мы создали тип Subscription с одним событием — messageAdded, которое возвращает объект типа Message.

3. Создание Event Publisher (генератор событий)

Теперь реализуем механизм публикации событий. Используем Spring Flux и реактивные потоки из Project Reactor.

Добавим класс MessagePublisher:


import org.springframework.stereotype.Component;
import reactor.core.publisher.Flux;
import reactor.core.publisher.FluxSink;

import java.util.ArrayList;
import java.util.List;

@Component
public class MessagePublisher {

    private final List<String> messages = new ArrayList<>();
    private FluxSink<String> sink;

    public Flux<String> getPublisher() {
        return Flux.create(emitter -> this.sink = emitter);
    }

    public void addMessage(String message) {
        messages.add(message);
        if (sink != null) {
            sink.next(message); // Публикуем новое сообщение
        }
    }
}

4. Реализация подписки в GraphQL

Теперь создадим подписку в Spring GraphQL. Добавим класс MessageSubscription.


import org.springframework.graphql.data.method.annotation.SubscriptionMapping;
import org.springframework.stereotype.Controller;
import reactor.core.publisher.Flux;

@Controller
public class MessageSubscription {

    private final MessagePublisher messagePublisher;

    public MessageSubscription(MessagePublisher messagePublisher) {
        this.messagePublisher = messagePublisher;
    }

    @SubscriptionMapping
    public Flux<String> messageAdded() {
        return messagePublisher.getPublisher();
    }
}

Метод messageAdded подписывается на поток событий, и как только в MessagePublisher будет добавлено новое сообщение, оно сразу отправится клиенту.

5. Изменение существующего сервиса для публикации событий

Обновим сервис, добавляющий сообщения, чтобы он публиковал их через наш MessagePublisher.


import org.springframework.stereotype.Service;

@Service
public class MessageService {

    private final MessagePublisher messagePublisher;

    public MessageService(MessagePublisher messagePublisher) {
        this.messagePublisher = messagePublisher;
    }

    public void addNewMessage(String message) {
        messagePublisher.addMessage(message);
        System.out.println("Сообщение добавлено: " + message);
    }
}

Тестирование подписок

Для тестирования подписок используйте GraphQL Playground или Altair. Обе эти утилиты поддерживают WebSocket соединения.

1. Запустите приложение.

2. Откройте GraphQL Playground и выполните подписку:


subscription {
  messageAdded
}

3. В другом окне GraphQL отправьте мутацию для добавления сообщения:


mutation {
  addMessage(text: "Привет, GraphQL!") {
    id
    text
    timestamp
  }
}

Если всё настроено правильно, вы мгновенно увидите в окне подписки новое сообщение. Момент магии!


Построение реактивных приложений с подписками

Подписки идеально интегрируются с реактивным подходом. Используя WebFlux вместо классических потоков, вы можете создавать реактивные приложения, которые способны обрабатывать тысячи подписчиков одновременно с минимальными накладными расходами.

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


Типовые ошибки и советы

Работа с подписками не обходится без распространённых ловушек. Например:

  • WebSocket соединение не устанавливается. Проверьте, включён ли у вас WebSocket в приложении и корректно ли настроен транспорт GraphQL.
  • События приходят с задержкой. Это может быть вызвано отсутствием реальной асинхронной обработки событий.
  • Пропадающие сообщения. Если клиент отключается, то текущая реализация MessagePublisher теряет данные. Для критичных систем стоит добавить буфер или использовать брокер сообщений (например, Kafka).

Овладение механизмом подписок в GraphQL открывает перед вами путь к созданию высокоинтерактивных приложений. Успехов в разработке!

Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ