Site icon Vinsguru

Spring WebFlux Streaming

spring webflux streaming

Overview:

In this tutorial, I would like to demo Spring WebFlux Streaming Response (aka Server Sent Events) – a mechanism for pushing notifications/messages to the browsers from the back-end application in real time.

Spring WebFlux Streaming:

Traditionally browsers have to make a request to the server to fetch the latest information. It has worked just fine so far. When we have to do periodic polling like this, most of the times there might not be any updates! When we have multiple clients bombarding the server every second for updates when there are not much updates, it is simply wasting resources and makes unnecessary network calls.

Server Sent Events is a standard for transmitting data to the client applications using the persistent connection established between the client and the server.  With Server Sent Events (SSE / Event Stream) approach, our server notifies the browser when the server has some updates in more efficient way.

This can be easily achieved by using Spring WebFlux Streaming response.

Sample Application:

Let’s consider a simple application for people having depression. Our application continuously publishes Jokes every 3 seconds & keep the clients happy.

Jokes API:

We will be using below URL to get random jokes. It is a simple GET request without any authentication.

https://joke.deno.dev/

The response payload is as shown below. Jokes are in the Q & A format.

{
   "id":120,
   "type":"general",
   "setup":"How do hens stay fit?",
   "punchline":"They always egg-cercise!"
}

Project Setup:

Create a simple Spring Boot application with these dependencies.

Joke – DTO:

Let’s start with creating a simple DTO class for the Joke object.

@Data
public class Joke implements Serializable {

    private String setup;
    private String punchline;

}

Application Configuration:

In our configuration class we create couple of beans.

@Configuration
public class AppConfiguration {

    private static final String JOKE_API_ENDPOINT = "https://joke.deno.dev/";

    @Bean
    public WebClient webClient(){
        return WebClient.builder()
                    .baseUrl(JOKE_API_ENDPOINT)
                    .build();
    }

    @Bean
    public Sinks.Many<Joke> sink(){
        return Sinks.many().replay().latest();
    }

    @Bean
    public Flux<Joke> flux(Sinks.Many<Joke> sink){
        return sink.asFlux().cache();
    }

}

Service:

Here we create a Spring component / service. We autowire the webclient and sink instances. We make the call to the public API periodically to get random jokes and pass it to the sink instance. That is it.

@Service
public class JokePublisher {

    @Autowired
    private WebClient webClient;

    @Autowired
    private Sinks.Many<Joke> sink;

    @Scheduled(fixedRate = 3000)
    public void publish(){
        this.webClient
                .get()
                .retrieve()
                .bodyToMono(Joke.class)
                .subscribe(this.sink::tryEmitNext);
    }

}

Spring WebFlux Streaming – Server Side:

Our rest controller has a single endpoint. We autowire the Flux instance here through which our clients/browsers subscribe to the Jokes. Whenever the client makes a request to the /joke endpoint,  the client is subscribing to the Flux which keeps on publishing new jokes whenever it receives new one!

@RestController
public class StreamController {

    @Autowired
    private Flux<Joke> flux;

    @GetMapping(value = "joke", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<Joke> getJoke(){
        return flux;
    }

}

Spring WebFlux Streaming – Client Side:

Our server side application is ready! We can test this directly by calling the joke endpoint. But Lets create a simple index.html with bootstrap theme to test the complete end-to-end behavior.

The index.html contains a div like this.

<!-- Page Content -->
  <div class="container">
    <div class="row">
      <div class="col-lg-12 text-center">
        <h1 class="mt-5">Joke of this moment!</h1>
        <p class="lead">This site will keep you laughing every 3 seconds using Server sent events!</p>
        <div class="card text-left mt-5" style="width: 80rem">
          <div class="card-header" id="qn">
            Joke Qn
          </div>
          <ul class="list-group list-group-flush">
            <li class="list-group-item" id="ans">Joke Ans</li>
          </ul>
        </div>
      </div>
    </div>
  </div>

The browser would keep getting new jokes every 3 seconds via Event stream. The browser should subscribe to our flux. The browser does not have to be refreshed.

The client side javascript is very simple as shown here. We just give the endpoint to subscribe to. The event.data contains the DTO information from which we get the specific information (like setup and punchline) and update our HTML.

var source = new EventSource("joke");
source.onmessage = function(event) {
  let data = JSON.parse(event.data);
  document.getElementById("qn").innerHTML = data.setup;
  document.getElementById("ans").innerHTML = data.punchline;
};

Spring WebFlux Streaming – Demo:

That’s it! Let’s run the application and look at the application behavior.

Summary:

We were able to successfully demonstrate Spring WebFlux Streaming response (Server Sent Events  / SSE / Event Stream). You could ask how to send specific messages to specific clients when there are multiple subscribers. It can be done very easily as well! Check out below article which I had done with MongoDB.

Learn more on Spring WebFlux.

The source code is available here.

Happy learning 🙂

 

Share This:

Exit mobile version