How to create a Spring WebFlux Application

A step-by-step guide to create a Spring WebFlux sample application and expose reactive REST API built on Spring Spring Boot and Spring WebFlux.

Overview

Spring WebFlux is a web development framework that uses reactive steams to process requests. Because of the reactive streams, request processing in the WebFlux application happens in reactive and non-blocking way.

In this tutorial we’ll create a Spring WebFlux Example Application, which is a Spring WebFlux REST Service built on Spring Boot and Reactor Netty. Aim is to get hands on with the Spring WebFlux framework and building non-blocking REST Endpoints.

This article uses annotation based controllers to build Spring WebFlux reactive REST service. However, we can also use Spring Functional Web Framework and build REST APIs without using annotation based controllers.

Read Using Functional Web Framework in Spring WebFlux Application to build Functional Router (router functions) based REST API in WebFlux)

Spring WebFlux

The motivation behind Spring WebFlux project is to provide a reactive web development project that is similar to Spring MVC or Spring MVC with async. Spring MVC is fully synchronous and blocking web framework. However, it can be used with Spring Async bring in asynchronous request processing. But, it doesn’t support non-blocking IO.

Spring WebFlux is uses Project Reactor core libraries to provide a fully non-blocking web framework. Also, it supports basic Spring web annotations. Thus, if you already know Spring MVC, you will find WebFlux controllers a lot similar. As we have already covered Spring WebFlux and Reactive API in Spring WebFlux and Reactive API Guide, in this tutorial we will focus building a WebFlux application. In the next section we will create a Reactive REST Service based on Spring Boot and Spring WebFlux.

Reactive REST Application with Spring WebFlux

As part of this tutorial, we will build a Students service that provides reactive REST endpoints. In order to keep the things simple we will consider a very basic model and use a mock data service.

Endpoints

The REST API will have next two endpoints.

  • GET /students/{sudentId}
  • GET /students

The purpose of choosing these two endpoints it to effectively demonstrate usage of reactive publishers like Flux and Mono.

Model

To build a Student service we will create a Student DTO object.

Student.java

public class Student {
    private final Long studentId;
    private final String firstName;
    private final String lastName;
    private final Integer year;

    public Student(Long studentId, String firstName, String lastName, Integer year) {
        this.studentId = studentId;
        this.firstName = firstName;
        this.lastName = lastName;
        this.year = year;
    }

    // Getters and Setters
}Code language: Java (java)

Dependency

In order to build a Spring Boot based application, we first need to create a basic Spring Boot Project. The best way to build a basic Spring Boot project is to use Spring Initializr.

After that, we need to add Spring WebFlux dependency. Spring WebFlux comes with a Spring Boot starter dependency spring-boot-starter-webflux.

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>Code language: HTML, XML (xml)

The starter dependency implicitly brings in

  • Spring Web
  • Spring WebFlux
  • Spring Boot Starter
  • Spring Boot Starter Json
  • and, Spring Boot Starter Reactor Netty.

In short, spring-boot-starter-webflux is the only required dependency for this tutorial. Also note that the dependency implicitly installs Reactor Netty, which is a reactive Web server. On the other hand any normal Spring Boot application implicitly installs Tomcat.

Rest Controller

Next, we will create a REST Controller that has two endpoints – single resource endpoint and multi-resource endpoint.

A normal blocking type of Controller returns resources directly.

public List<Student> getStudents(){...}Code language: Java (java)

However, because of this the clients of the endpoint will remain blocked for the time it takes for the server to prepare and return the list of Student.

On the other hand, non-blocking controllers – in WebFlux, return a publisher that can emit the results when client wants to consume them.

public Mono<Student> getStudent(@PathVariable Long studentId) {...}Code language: Java (java)

That makes them non-blocking web endpoints.

That is why, instead of returning pre-fetched results, our WebFlux controller returns publishers. The endpoint returning a single resource return a publisher of type Mono. While the endpoint that returns multiple resources returns a Flux publisher.

@RestController
public class StudentController {

    public final StudentService service;

    public StudentController(StudentService service) {
        this.service = service;
    }

    @GetMapping("/students/{studentId}")
    public Mono<Student> getStudent(@PathVariable Long studentId) {
        return service.getStudent(studentId);
    }

    @GetMapping("/students")
    public Flux<Student> getStudents() {
        return service.getStudents();
    }
}Code language: Java (java)

As seen here, WebFlux controller supports Spring Web annotations – like @GetMapping and @RestController, @PathVariable etc.

Service Class

We will create a service class that supports the REST endpoint methods. The service layer returns a mock data in the form of reactive publishers – Mono and Flux.

@Service
public class StudentService {
    public Mono<Student> getStudent(Long studentId) {
        return Mono.just(new Student(studentId, "firstName", "lastName", 2030));
    }

    public Flux<Student> getStudents() {
        return Flux.just(
                new Student(1L, "firstName1", "lastName1", 2030),
                new Student(2L, "firstName2", "lastName2", 2030),
                new Student(3L, "firstName3", "lastName3", 2030)
        );
    }
}Code language: Java (java)

Note that, the method getStudent(studentId) can return only one student at max. Thus it returns a Mono of Student. On the other hand getStudents() method may return N number of students. That is why it returns a Flux of Student.

In a read life application, the service layer will fetch the data from various resources like database, other service, or file system etc. However, as the tutorial focuses building reactive web application, we have kept them out of scope.

Use WebClient to Test

Spring WebClient is a reactive and non-blocking tool to execute HTTP requests. We won’t discuss basics of WebClient here as we have a detailed discussion at Introduction to Spring WebClient.

WebClients can be created easily using its builder and reused. For example, we are creating a WebClient instance in a @Bean factory method.

@Bean
public WebClient webClientBuilder() {
    return WebClient.builder()
            .baseUrl("http://localhost:8080")
            .build();
}Code language: Java (java)

Retrieve Single Resource

In order to execute and consume reactive REST API that returns a single resource, the WebClient needs to covert the response body to Mono.

Mono<Student> studentMono = webClient
        .get()
        .uri("/students/{studentId}", 2L)
        .retrieve()
        .onStatus(not(HttpStatus::is2xxSuccessful), clientResponse ->
                error(new StudentServiceException
                        ("Error while communicating to Student Service"))
        )
        .bodyToMono(Student.class);
studentMono.subscribe(System.out::println);Code language: Java (java)

Note, that the Mono#subscribe(consumer) method accepts a consumer. Hence, we have provided System#out#println() as a consumer. The subscribe operation on the Mono is blocking. Thus, output won’t be printed until server has completely sent the response.

Also, we are throwing a custom exception when we do not receive a successful status code.

Retrieve a Collection of Resource

Similarly, WebClient can be used to retrieve a collection of resource from an endpoints. To do so, we need to use bodyToFlux() method.

Flux<Student> studentMono = webClient
        .get()
        .uri("/students/")
        .retrieve()
        .onStatus(not(HttpStatus::is2xxSuccessful), clientResponse ->
                error(new StudentServiceException
                        ("Error while communicating to Student Service"))
        )
        .bodyToFlux(Student.class);
studentMono.subscribe(System.out::println);Code language: Java (java)

Summary

In this tutorial we have covered an Example of Reactive REST Application using Spring WebFlux. We followed a step by step approach and created a Spring Boot application from scratch.

We learned that Spring WebFlux controllers are very much similar to any Spring MVC Controllers. The only difference is that, instead of returning actual resource the WebFlux controllers return Publisher that produce those resources. When a controller wants to return a single resource is returns publisher of type Mono, or return Flux if a collection of resources is to be returned.

Lastly, we also tested our Reactive REST API using Spring WebClient – a reactive HTTP client and correctly read the results in Flux and Mono.