Subscriptions in GraphQL (from the English Subscriptions) are a mechanism for receiving data from the server in real time without having to re-send requests. Put simply, subscriptions let users "listen" to certain events or data changes so they receive notifications as soon as those events happen.
Subscriptions make your app more dynamic and interactive. Imagine:
- Chat app that updates messages in real time without needing to refresh the page.
- Online auction where users instantly see new bids.
- Live sports streaming that updates the match score in real time.
Subscriptions replace clunky approaches like periodic polling or long-lived HTTP requests.
How do subscriptions in GraphQL work?
Subscriptions use WebSocket to establish a persistent connection between the client and server. When a client subscribes to a certain event, the server keeps the channel open and pushes updates as they occur. It's like subscribing to a newsletter — you subscribe once and then get notifications.
Example of a subscription for a new chat message in GraphQL:
subscription OnNewMessage {
newMessage(chatId: "123") {
id
content
sender {
name
}
timestamp
}
}
Subscription components
- GraphQL schema: defines the data types that will be returned by the subscription.
- Event Publisher: the mechanism for generating events on the server (Spring Boot uses Project Reactor for reactive streams).
- WebSocket transport: provides the two-way communication between client and server.
Implementing subscriptions in Spring GraphQL
Let's set up subscriptions for your Spring Boot app with GraphQL together.
1. Adding dependencies
To work with subscriptions you need to add dependencies to pom.xml. Don't forget to include the GraphQL WebSocket transport!
<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>
After adding dependencies remember that magical mvn clean install command so Maven will pull everything you need.
2. Creating the subscription schema
Create a file named schema.graphqls and describe your subscription.
type Subscription {
messageAdded: Message
}
type Message {
id: ID
text: String
sender: String
timestamp: String
}
Here we created a Subscription type with one event — messageAdded, which returns an object of type Message.
3. Creating an Event Publisher
Now let's implement the event publishing mechanism. We'll use Spring Flux and reactive streams from Project Reactor.
Add the MessagePublisher class:
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); // Publish new message
}
}
}
4. Implementing the subscription in GraphQL
Now create the subscription in Spring GraphQL. Add the MessageSubscription class.
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();
}
}
The messageAdded method subscribes to the event stream, and as soon as a new message is added in MessagePublisher it will be sent to the client immediately.
5. Updating the existing service to publish events
Update the service that adds messages so it publishes them via our 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 added: " + message);
}
}
Testing subscriptions
To test subscriptions use GraphQL Playground or Altair. Both tools support WebSocket connections.
1. Start the application.
2. Open GraphQL Playground and run the subscription:
subscription {
messageAdded
}
3. In another window send a mutation to add a message:
mutation {
addMessage(text: "Hello, GraphQL!") {
id
text
timestamp
}
}
If everything is set up correctly you'll instantly see the new message in the subscription window. A little bit of magic!
Building reactive apps with subscriptions
Subscriptions fit perfectly with the reactive approach. By using WebFlux instead of classic blocking threads, you can build reactive applications that handle thousands of subscribers concurrently with minimal overhead.
Practical example: building a notification system that pushes updates to all subscribed users, no matter how many there are.
Common mistakes and tips
Working with subscriptions comes with common pitfalls. For example:
- WebSocket connection won't establish. Check that WebSocket is enabled in your app and that the GraphQL transport is configured correctly.
- Events arrive with delay. This can be caused by a lack of true asynchronous event handling.
- Missing messages. If the client disconnects, the current
MessagePublisherimplementation loses data. For critical systems add a buffer or use a message broker (for example, Kafka).
Mastering the Subscriptions mechanism in GraphQL opens the path to building highly interactive applications. Good luck with your development!
GO TO FULL VERSION