0Pricing
GraphQL APIs with Spring Boot · Lesson

Implementing Real-time Updates

Develop subscription resolvers in Spring Boot to publish events and send live data to clients.

Implementing Real-time Updates is a free GraphQL APIs with Spring Boot lesson on CoddyKit — lesson 2 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the GraphQL APIs with Spring Boot learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

Subscription Resolvers Explained

Subscriptions deliver real-time updates. Unlike queries that return data once, subscription resolvers return a stream of data that continuously pushes updates to clients.

We'll learn how to implement these streams in a Spring Boot GraphQL application.

Embracing Reactor Flux

Spring GraphQL leverages Project Reactor's Flux to handle subscriptions. A Flux represents an asynchronous, non-blocking stream of 0 to N items.

  • It's ideal for continuous data delivery.
  • You can emit multiple values over time.

Schema for Real-time Updates

First, we define our subscription in the GraphQL Schema Definition Language (SDL). This example shows a subscription for new messages:

type Subscription {
  messageAdded(channelId: ID!): Message
}

type Message {
  id: ID!
  text: String!
  channelId: ID!
  timestamp: String!
}

Creating a Subscription Resolver

In Spring Boot, a subscription resolver is a method annotated with @SubscriptionMapping. It must return a Flux of the desired type.

We'll use a Sinks.Many to manage and publish events into this stream.

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

@Controller
public class MessageSubscriptionController {

    private final Sinks.Many<Message> messageSink = 
        Sinks.many().multicast().onBackpressureBuffer();

    @SubscriptionMapping
    public Flux<Message> messageAdded() {
        return messageSink.asFlux();
    }
}

Publishing Events with Sinks.Many

The Sinks.Many instance acts as our event publisher. When an event occurs (e.g., a new message is created), we use its tryEmitNext() method to send data into the stream.

This data then flows through the Flux to all connected GraphQL subscribers.

public class MessageService {

    private final Sinks.Many<Message> messageSink;

    public MessageService(Sinks.Many<Message> messageSink) {
        this.messageSink = messageSink;
    }

    public Message createMessage(String text, String channelId) {
        // ... save message to DB ...
        Message newMessage = new Message("1", text, channelId, "now");
        messageSink.tryEmitNext(newMessage); // Publish the new message
        return newMessage;
    }
}

Full Runnable Example Setup

Let's build a complete, runnable Spring Boot application. We'll define a Message record and a MessagePublisher component to manage our Sinks.Many.

record Message(String id, String text, String channelId, String timestamp) {}

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

@Component
public class MessagePublisher {
    private final Sinks.Many<Message> messageSink = 
        Sinks.many().multicast().onBackpressureBuffer();

    public Flux<Message> getMessageStream() {
        return messageSink.asFlux();
    }

    public void publishMessage(Message message) {
        messageSink.tryEmitNext(message);
    }
}

Main Application & Resolver

Now, we connect our MessagePublisher to the @SubscriptionMapping resolver. The Main class simulates sending a message after a delay.

Run this example to see the server-side publishing in action!

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.graphql.data.method.annotation.SubscriptionMapping;
import org.springframework.stereotype.Controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.time.Duration;

@SpringBootApplication
public class Main implements CommandLineRunner {

    @Autowired
    private MessagePublisher messagePublisher;

    public static void main(String[] args) {
        SpringApplication.run(Main.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        // Simulate sending a message after 2 seconds
        Mono.delay(Duration.ofSeconds(2))
            .subscribe(l -> {
                Message msg = new Message("2", "Hello from Spring!", "general", "now");
                messagePublisher.publishMessage(msg);
                System.out.println("Published: " + msg);
            });
    }
}

@Controller
class MessageSubscriptionController {
    private final MessagePublisher messagePublisher;

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

    @SubscriptionMapping
    public Flux<Message> messageAdded() {
        return messagePublisher.getMessageStream();
    }
}

record Message(String id, String text, String channelId, String timestamp) {}

Filtering Subscription Events

Clients often need updates specific to certain criteria. We can filter the Flux based on arguments passed to the subscription.

Here, clients only receive messages for a specified channelId.

import org.springframework.graphql.data.method.annotation.Argument;
// ... other imports ...

@Controller
class MessageSubscriptionController {
    private final MessagePublisher messagePublisher;

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

    @SubscriptionMapping
    public Flux<Message> messageAdded(@Argument String channelId) {
        return messagePublisher.getMessageStream()
            .filter(msg -> msg.channelId().equals(channelId));
    }
}

Decoupling Event Publishing

For better architecture, it's a good practice to decouple event publishing from your core business logic.

  • This keeps your services clean and focused.
  • It allows multiple independent subscribers to react to the same event without tight coupling.
  • Consider using Spring's ApplicationEventPublisher or a dedicated event bus for this.

Subscription Resolver Check

You've learned how to implement subscription resolvers in Spring Boot. Let's test your understanding!

Recap: Real-time Updates

You've successfully learned how to implement real-time updates using GraphQL subscriptions in Spring Boot!

  • Subscription resolvers return a Flux.
  • Sinks.Many is used to publish events into the Flux.
  • You can filter streams based on subscription arguments.
  • Decoupling publishing logic improves maintainability.

Frequently asked questions

Is the “Implementing Real-time Updates” lesson free?

Yes — the full text of “Implementing Real-time Updates” is free to read here on the web, and the GraphQL APIs with Spring Boot course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the GraphQL APIs with Spring Boot course, upgrade to CoddyKit PRO.

What will I learn in “Implementing Real-time Updates”?

Develop subscription resolvers in Spring Boot to publish events and send live data to clients. You practise GraphQL APIs with Spring Boot with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start GraphQL APIs with Spring Boot?

No prior experience is required. GraphQL APIs with Spring Boot on CoddyKit is structured for beginners through advanced learners; this is — lesson 2 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “Implementing Real-time Updates” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this GraphQL APIs with Spring Boot lesson?

Yes. Every GraphQL APIs with Spring Boot lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. Understanding GraphQL Subscriptions
  2. Implementing Real-time Updates
  3. Integrating WebSockets with Spring
  4. Filtering and Scaling Subscriptions
← Back to GraphQL APIs with Spring Boot