Testing Spring WebFlux Reactive CRUD Rest APIs Using WebTestClient
Last Updated :
24 Apr, 2025
Spring Boot is one of the famous frameworks for Back-end development. The Spring Boot Community Developed the Spring Reactive Web Framework. This Reactive Framework is available from Spring Boot 5.0 and Above versions only. The Spring Reactive allows developers to build Asynchronous, Non-Blocking, and Event-Driven Web Applications. When compared with the Spring MVC framework the Spring Reactive Web framework provides more functionality. And we can easily manage the web applications through this Spring Reactive Framework. If we want to use this framework, we need to integrate Spring Web flux in our dependencies File.
For Developing this project, we have used MongoDB as a database, here every CRUD Operation we have created one REST API endpoint, These API endpoints are defined by using RouterFunction and It returns a route function.
- In CRUD operation C indicates creating data in MongoDB for this we have created a REST API endpoint, This API takes input in the form of JSON format.
- The R indicates Retrieve operation, which means we can Retrieve all existing data, or by using ID also we can Retrieve data from the Database.
- Next U indicates Update operation in CRUD, we can be able to update existing data by using ID.
- The Final one is D indicates the delete operation. We can delete data from MongoDB by using the existing ID or Delete all Data.
Prerequisites:
To understand or create this project you have strong knowledge of Listed Concepts.
- Creation of Spring Boot Starter Project
- Knowledge in Java Programming
- Strong Knowledge in Spring WebFlux Reactive framework
- Basics of MongoDB
- REST API functionality
Tools and Technologies:
Below are the Tools and Technologies, we have used to create this project.
- Spring Tools Suite
- MongoDB
- Spring WebFlux Reactive Framework
- REST APIs
Project Creation:
- Open Spring Tool Suite Select a New project which Spring Stater type.
- After that select Project Category like maven or gradle, here we have used Gradle.
- Then provide the project name, package name, and other things.
- Click on next, then will get another screen, in this screen we need select Dependencies for our project.
- Now click on finish.
Project Folder Structure:

Project Dependencies:
In this project, we have used below Dependencies and the Project category is gradle.
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-mongodb-reactive'
implementation 'org.springframework.boot:spring-boot-starter-webflux'
compileOnly 'org.projectlombok:lombok'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'io.projectreactor:reactor-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}
MongoDB Connection with Spring Reactive
In application.properties file, configure the database connection with required properties.
spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
spring.data.mongodb.database=working
Spring WebFlux Reactive CRUD Rest APIs using WebTestClient
In this project, main package we have created different classes for different purposes. Each java class perform different actions. We can observe in the Project Folder image above. Below we have listed all the classes and explained with their functionality.
Student POJO class:
Here, we have created one POJO class handling Database operations by using lombok dependency. This provides setters and getters with all types of constructors. This class have three attributes namely id, studentName, studentAge. The id is automatically generated by the MongoDB while creating new record in collection.
Java
package com.webflux.app;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Document(collection = "student")
public class Student {
@Id
private String id;
private String studentName;
private String studentAge;
}
UserRepo Interface
This UserRepo interface is used for performing database related operation on Student model class. This interface extends to ReactiveMongoRepository. This repository is created by using @Repository, @EnableReactiveMongoRepositories. And ReactiveMongoRepository take two arguments as input those are targeted POJO class and It's Id data type.
Java
package com.webflux.app;
import org.springframework.data.mongodb.repository.ReactiveMongoRepository;
import org.springframework.data.mongodb.repository.config.EnableReactiveMongoRepositories;
import org.springframework.stereotype.Repository;
@Repository
@EnableReactiveMongoRepositories
public interface UserRepo extends ReactiveMongoRepository<Student, String> {
}
ServiceHandler class
This is a service layer for creating API logic here. In this class, we have created four APIs for performing CRUD operation by using REST API. Here The service class is created by using @Service annotation, then by using UserRepo we perform the CRUD operation.
Java
package com.webflux.app;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;
@Service
public class ServiceHandler {
@Autowired
private UserRepo userRepo;
public Mono<ServerResponse> addStudent(ServerRequest request) {
return request.bodyToMono(Student.class).flatMap(data -> {
return ServerResponse.ok().body(userRepo.save(data), Student.class);
});
}
public Mono<ServerResponse> deleteStudentById(ServerRequest request) {
return request.bodyToMono(Student.class).flatMap(data -> {
return ServerResponse.ok().body(userRepo.deleteById(data.getId()), Student.class);
}).switchIfEmpty(ServerResponse.ok().bodyValue("No Student Data Found"));
}
public Mono<ServerResponse> updateStudentById(ServerRequest request) {
return request.bodyToMono(Student.class).flatMap(data -> {
return userRepo.findById(data.getId()).flatMap(change -> {
change.setId(data.getId());
change.setStudentName(data.getStudentName());
change.setStudentAge(data.getStudentAge());
return ServerResponse.ok().body(userRepo.save(change), Student.class);
}).switchIfEmpty(ServerResponse.ok().bodyValue("No Student Data Found"));
});
}
public Mono<ServerResponse> getAllStudents(ServerRequest request) {
return request.bodyToMono(Student.class).flatMap(data -> {
return ServerResponse.ok().body(userRepo.findAll(), Student.class);
}).switchIfEmpty(ServerResponse.ok().bodyValue("No Student Data Found"));
}
}
ServiceRouter class
This another Java class for handling REST API end point. This class is created by using @Configuration annotation and this class have one bean that is RouterFunction. This bean creates routing end points for ServiceHandler API logic's. This router class have four REST API end points to handle CRUD operations.
Java
package com.webflux.app;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.server.RequestPredicates;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerResponse;
@Configuration
public class ServiceRouter {
@Autowired
private ServiceHandler serviceHandler;
@Bean
RouterFunction<ServerResponse> routerFunction(){
return RouterFunctions.route(RequestPredicates.POST("api/student/add"),serviceHandler::addStudent)
.andRoute(RequestPredicates.POST("api/student/delete"), serviceHandler::deleteStudentById)
.andRoute(RequestPredicates.POST("api/student/update"), serviceHandler::updateStudentById)
.andRoute(RequestPredicates.POST("api/student/getall"), serviceHandler::getAllStudents)
;
}
}
addStudent REST API
This API logic is used for creating a new Student row in the Collection. Here, we have used Mono Publisher and It return ServerResponse as a output. In this, first we convert Student POJO class body to Mono publisher by using bodyToMono(). Then we have created one flatmap , in this, we have created one lambda expression for save the data. Here, we save the Student data by using object of UserRepo repository. And It's REST API URL is defined in ServiceRouter.
REST API URL : api/student/add
Java
public Mono<ServerResponse>
addStudent(ServerRequest request)
{
return request.bodyToMono(Student.class)
.flatMap(data -> {
return ServerResponse.ok().body(
userRepo.save(data), Student.class);
});
}
When we test this API URL by using POSTMAN tool, successfully data is inserted into a Collection. Below is the output image for your reference. When we hit this API URL the data is saved into collection and return that saved record as a output.
Output:

deleteStudentById REST API
This API logic is used for delete a existing student data by using Student id, If id is available student data will be deleted otherwise It gives some error message as output. In this API logic we have created one flatmap for finding id, If id exist then deleted otherwise switchIfEmpty() method is executed.
REST API URL : api/student/delete
Java
public Mono<ServerResponse> deleteStudentById(ServerRequest request) {
return request.bodyToMono(Student.class).flatMap(data -> {
return ServerResponse.ok().body(userRepo.deleteById(data.getId()), Student.class);
}).switchIfEmpty(ServerResponse.ok().bodyValue("No Student Data Found"));
}
Output:

updateStudentById REST API
This API is used for update the existing Student data by using the Student ID. If Student Id not found it gives an error message other wise successfully update new data for existing id then return the new data as server response. We can observe this in the output image below.
REST API URL : api/student/update
Java
public Mono<ServerResponse> updateStudentById(ServerRequest request) {
return request.bodyToMono(Student.class).flatMap(data -> {
return userRepo.findById(data.getId()).flatMap(change -> {
change.setId(data.getId());
change.setStudentName(data.getStudentName());
change.setStudentAge(data.getStudentAge());
return ServerResponse.ok().body(userRepo.save(change), Student.class);
}).switchIfEmpty(ServerResponse.ok().bodyValue("No Student Data Found"));
});
}
Output:

getAllStudents REST API
This REST API return all existing student data from collection, below is the Java code and Its output image for understanding in better way.
REST API URL : api/student/update
Java
public Mono<ServerResponse> getAllStudents(ServerRequest request) {
return request.bodyToMono(Student.class).flatMap(data -> {
return ServerResponse.ok().body(userRepo.findAll(), Student.class);
}).switchIfEmpty(ServerResponse.ok().bodyValue("No Student Data Found"));
}
We have two documents only, when we hit this API return that two Records data from Database. Below is the output image.
Output:

WebTestClient
The WebTestClient is an HTTP client used for testing Server related Applications. In our case in the above we developed Reactive REST APIs. Now we need Test those APIs. Then we get a conclusion means the APIs working properly or not. For understanding his Testing code, you should have knowledge in testing. Below we have provided the Test code. Write this testing code in Test class. This class available in Project Test package. Below we have provided the Testing code for four APIs with output image for your reference.
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureWebTestClient
With out these Spring Boot Annotations with given properties, We have a chance to get errors.
Java
package com.webflux.app;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;
import org.springframework.test.web.reactive.server.WebTestClient;
import org.springframework.web.reactive.function.server.ServerResponse;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureWebTestClient
class WebFluxApplicationTests {
@Autowired
private WebTestClient webTestClient;
@MockBean
private ServiceHandler serviceHandler;
@Test
public void testaddStudent() {
Student student = new Student();
student.setStudentName("John");
student.setStudentAge("21");
when(serviceHandler.addStudent(any())).thenReturn(ServerResponse.ok().bodyValue(student));
webTestClient.post().uri("/api/student/add").contentType(MediaType.APPLICATION_JSON)
.bodyValue(student).exchange().expectStatus().isOk().expectBody(Student.class)
.isEqualTo(student);
}
@Test
public void testdeleteStudentById() {
Student student = new Student();
student.setId("1234");
when(serviceHandler.deleteStudentById(any())).thenReturn(ServerResponse.ok().bodyValue(student));
webTestClient.post().uri("/api/student/delete").contentType(MediaType.APPLICATION_JSON)
.bodyValue(student).exchange().expectStatus().isOk().expectBody(Student.class)
.isEqualTo(student);
}
@Test
public void testupdateStudentById() {
Student student = new Student();
student.setId("1234");
student.setStudentName("John");
student.setStudentAge("21");
when(serviceHandler.updateStudentById(any())).thenReturn(ServerResponse.ok().bodyValue(student));
webTestClient.post().uri("/api/student/update").contentType(MediaType.APPLICATION_JSON)
.bodyValue(student).exchange().expectStatus().isOk().expectBody(Student.class)
.isEqualTo(student);
}
@Test
public void testgetAllStudents() {
Student student = new Student();
when(serviceHandler.getAllStudents(any())).thenReturn(ServerResponse.ok().bodyValue(student));
webTestClient.post().uri("/api/student/getall").contentType(MediaType.APPLICATION_JSON)
.bodyValue(student).exchange().expectStatus().isOk().expectBody(Student.class)
.isEqualTo(student);
}
}
Output:

Explaination of the above Program:
- First, we Autowired the ServerHandler class for accessing the APIs methods from Server layer.
- After that, we Autowired the WebTestClient to access the Service of the WebTestClient to test the applications means APIs.
- Then, we have created four test methods by using @Test, in each method, we have created Model class object to set and get the data while testing APIs.
- After this in each class we call the APIs methods by using ServiceHandler object with API URLs using when in Testing.
- Then we call the webTestClient object to testing the APIs URLs by using post method.
- After this Test class as Junit, Four APIs are successfully passed the Test cases. Below we have provided that output image.
Similar Reads
Spring WebFlux Reactive CRUD REST API Example
Spring WebFlux can be defined as the reactive programming framework provided by the Spring ecosystem for the building of asynchronous, non-blocking, and event-driven applications and it can be designed to handle a large number of concurrent connections while consuming less resources. Key Terminologi
5 min read
Creating REST APIs Using Spring WebFlux and MongoDB
Spring Boot is the most popular Java framework for building stand-alone Java-based applications quickly and with minimal configuration. WebFlux is a responsive operating system provided by the Spring framework for running non-blocking, asynchronous, and event-driven applications. On the other hand,
10 min read
Spring WebFlux REST Application Integration with Spring Data R2DBC
Spring WebFlux is the framework from the Spring ecosystem that supports reactive programming for building asynchronous and non-blocking web applications. Unlike the traditional Spring MVC, which can use the blocking I/O. WebFlux can be designed to handle large volumes of requests using fewer resourc
4 min read
Spring Boot - Reactive Programming Using Spring Webflux Framework
In this article, we will explore React programming in Spring Boot, Reactive programming is an asynchronous, non-blocking programming paradigm for developing highly responsive applications that react to external stimuli. What is Reactive ProgrammingIn reactive programming, the flow of data is asynchr
4 min read
Reactive JWT Authentication Using Spring WebFlux
JSON Web Token (JWT) authentication is a popular method for securing APIs in microservices architectures. With Spring WebFlux, the reactive web framework, we can create highly scalable and responsive applications. In this article, we will guide you on how to implement JWT authentication in a reactiv
8 min read
Security with Spring Security and Spring Webflux
Spring WebFlux is a part of the Spring Framework that supports reactive programming, enabling non-blocking asynchronous request handling. When developing web applications with Spring WebFlux, securing the application is a crucial aspect to ensure unauthorized access is prevented. This article provid
3 min read
Spring Cloud Gateway with Spring WebFlux
Spring Cloud Gateway is the library that allows you to build API gateways on top of Spring WebFlux. It provides a simple and effective way to route requests, apply filters, and manage cross-cutting concerns reactively. This article will guide you through demonstrating how to set up Spring Cloud Gate
5 min read
How to Redirect a Request in Spring WebFlux?
The Spring WebFlux is a part Spring Reactive framework. In Spring WebFlux, we can redirect requests by using the ServerResponse. This is one of the classes in Spring WebFlux which provides methods for creating responses. To direct a request in Spring WebFlux, we typically return the ServerResponse w
4 min read
Spring Webflux Websocket Security - Basic Authentication
Spring WebFlux WebSockets, the authentication data that was included in the HTTP request at the time the WebSocket connection was established is reused. This indicates that WebSockets will receive the Principal on the HttpServletRequest. The Principal on the HttpServletRequest is automatically overr
5 min read
Spring WebFlux Functional Endpoints CRUD REST API Example
Spring Boot is a Java framework for back-end development. Another miracle in Spring Boot is the Spring Boot Community has developed the Spring Reactive Web Framework i.e. Spring WebFlux. To develop this project, we have used the MongoDB database. Here, for every CRUD (Create, Retrieve, Update, Delet
7 min read