Подписки в GraphQL (от англ. Subscriptions) — это механизм получения данных от сервера в реальном времени, без необходимости повторно отправлять запросы. Если совсем просто, подписки позволяют пользователям "подключиться" к определённым событиям или изменениям данных, чтобы получать уведомления об этом сразу после их возникновения.
Подписки делают ваше приложение более динамичным и интерактивным. Представьте себе:
- Чат-приложение, которое обновляет сообщения в реальном времени, без необходимости рефреша страницы.
- Онлайн-аукцион, где пользователи моментально видят новые ставки.
- Спортивный стриминг, который в прямом эфире обновляет счёт матча.
Подписки заменяют "громоздкие" механизмы вроде периодической отправки запросов (polling) или долгоживущих HTTP-соединений.
Как устроены подписки в GraphQL?
Подписки используют WebSocket для установления постоянного соединения между клиентом и сервером. Когда клиент подписывается на определённое событие, сервер поддерживает открытый канал и отправляет обновления по мере их появления. Это как подписка на рассылку новостей — вы один раз подписываетесь, а дальше получаете уведомления.
Пример подписки на новое сообщение в чате на языке GraphQL:
subscription OnNewMessage {
newMessage(chatId: "123") {
id
content
sender {
name
}
timestamp
}
}
Компоненты подписок
- Схема GraphQL: задаёт типы данных, которые будут возвращаться по подписке.
- Event Publisher: механизм для генерации событий на сервере (Spring Boot использует Project Reactor для реактивных потоков).
- 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 открывает перед вами путь к созданию высокоинтерактивных приложений. Успехов в разработке!
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ