Testing Spring WebFlux Reactive CRUD Rest APIs Using WebTestClient
Last Updated :
23 Jul, 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 Boot Tutorial Spring Boot is a Java framework that makes it easier to create and run Java applications. It simplifies the configuration and setup process, allowing developers to focus more on writing code for their applications. This Spring Boot Tutorial is a comprehensive guide that covers both basic and advance
10 min read
Spring Boot Basics and Prerequisites
Introduction to Spring BootSpring is one of the most popular frameworks for building enterprise applications, but traditional Spring projects require heavy XML configuration, making them complex for beginners.Spring Boot solves this problem by providing a ready-to-use, production-grade framework on top of Spring. It eliminate
4 min read
Difference between Spring and Spring BootSpring Spring is an open-source lightweight framework that allows Java developers to build simple, reliable, and scalable enterprise applications. This framework mainly focuses on providing various ways to help you manage your business objects. It made the development of Web applications much easier
4 min read
Spring - Understanding Inversion of Control with ExampleSpring IoC (Inversion of Control) Container is the core of the Spring Framework. It creates and manages objects (beans), injects dependencies and manages their life cycles. It uses Dependency Injection (DI), based on configurations from XML files, Java-based configuration, annotations or POJOs. Sinc
6 min read
Spring - IoC ContainerThe Spring framework is a powerful framework for building Java applications. It can be considered a collection of sub-frameworks, also referred to as layers, such as Spring AOP, Spring ORM, Spring Web Flow, and Spring Web MVC. We can use any of these modules separately while constructing a Web appli
2 min read
BeanFactory vs ApplicationContext in SpringThe Spring Framework provides two core packages that enable Inversion of Control (IoC) and Dependency Injection (DI):org.springframework.beansorg.springframework.contextThese packages define Spring containers that manage the lifecycle and dependencies of beans.Spring offers two main containers1. Bea
6 min read
Spring Boot Core
Spring Boot - ArchitectureSpring Boot is built on top of the Spring Framework and follows a layered architecture. Its primary goal is to simplify application development by providing auto-configuration, embedded servers and a production-ready environment out of the box.The architecture of Spring Boot can be divided into seve
2 min read
Spring Boot - AnnotationsAnnotations in Spring Boot are metadata that simplify configuration and development. Instead of XML, annotations are used to define beans, inject dependencies and create REST endpoints. They reduce boilerplate code and make building applications faster and easier. Core Spring Boot Annotations 1. @Sp
5 min read
Spring Boot ActuatorDeveloping and managing an application are the two most important aspects of the applicationâs life cycle. It is very important to know what is going on beneath the application. Also, when we push the application into production, managing it gradually becomes critically important. Therefore, it is a
5 min read
How to create a basic application in Java Spring BootSpring Boot is the most popular Java framework that is used for developing RESTful web applications. In this article, we will see how to create a basic Spring Boot application.Spring Initializr is a web-based tool using which we can easily generate the structure of the Spring Boot project. It also p
3 min read
Spring Boot - Code StructureThere is no specific layout or code structure for Spring Boot Projects. However, there are some best practices followed by developers that will help us too. You can divide your project into layers like service layer, entity layer, repository layer,, etc. You can also divide the project into modules.
3 min read
Spring Boot - SchedulingSpring Boot provides the ability to schedule tasks for execution at a given time period with the help of @Scheduled annotation. This article provides a step by step guideline on how we can schedule tasks to run in a spring boot application Implementation:It is depicted below stepwise as follows:Â St
4 min read
Spring Boot - LoggingLogging in Spring Boot plays a vital role in Spring Boot applications for recording information, actions, and events within the app. It is also used for monitoring the performance of an application, understanding the behavior of the application, and recognizing the issues within the application. Spr
8 min read
Exception Handling in Spring BootException handling in Spring Boot helps deal with errors and exceptions present in APIs, delivering a robust enterprise application. This article covers various ways in which exceptions can be handled and how to return meaningful error responses to the client in a Spring Boot Project. Key Approaches
8 min read
Spring Boot with REST API
Spring Boot - Introduction to RESTful Web ServicesRESTful Web Services REST stands for REpresentational State Transfer. It was developed by Roy Thomas Fielding, one of the principal authors of the web protocol HTTP. Consequently, REST was an architectural approach designed to make the optimum use of the HTTP protocol. It uses the concepts and verbs
5 min read
Spring Boot - REST ExampleIn modern web development, most applications follow the Client-Server Architecture. The Client (frontend) interacts with the server (backend) to fetch or save data. This communication happens using the HTTP protocol. On the server, we expose a bunch of services that are accessible via the HTTP proto
4 min read
How to Create a REST API using Java Spring Boot?Representational State Transfer (REST) is a software architectural style that defines a set of constraints for creating web services. RESTful web services allow systems to access and manipulate web resources through a uniform and predefined set of stateless operations. Unlike SOAP, which exposes its
4 min read
How to Make a Simple RestController in Spring Boot?A RestController in Spring Boot is a specialized controller that is used to develop RESTful web services. It is marked with the @RestController annotation, which combines @Controller and @ResponseBody. This ensures that the response is automatically converted into JSON or XML, eliminating the need f
2 min read
JSON using Jackson in REST API Implementation with Spring BootWhen we build REST APIs with Spring Boot, we need to exclude NULL values from the JSON responses. This is useful when we want to optimize the data being transferred, making the response more compact and easier to process for the client.In this article, we are going to learn the approach that is used
4 min read
Spring Boot with Database and Data JPA
Spring Boot with Kafka
Spring Boot Kafka Producer ExampleSpring Boot is one of the most popular and most used frameworks of Java Programming Language. It is a microservice-based framework and to make a production-ready application using Spring Boot takes very less time. Spring Boot makes it easy to create stand-alone, production-grade Spring-based Applica
3 min read
Spring Boot Kafka Consumer ExampleSpring Boot is one of the most popular and most used frameworks of Java Programming Language. It is a microservice-based framework and to make a production-ready application using Spring Boot takes very less time. Spring Boot makes it easy to create stand-alone, production-grade Spring-based Applica
3 min read
Spring Boot | How to consume JSON messages using Apache KafkaApache Kafka is a stream processing system that lets you send messages between processes, applications, and servers. In this article, we will see how to publish JSON messages on the console of a Spring boot application using Apache Kafka. In order to learn how to create a Spring Boot project, refer
3 min read
Spring Boot | How to consume string messages using Apache KafkaApache Kafka is a publish-subscribe messaging queue used for real-time streams of data. A messaging queue lets you send messages between processes, applications, and servers. In this article we will see how to send string messages from apache kafka to the console of a spring boot application. Appro
3 min read
Spring Boot | How to publish String messages on Apache KafkaApache Kafka is a publish-subscribe messaging system. A messaging queue lets you send messages between processes, applications, and servers. In this article, we will see how to send string messages to Apache Kafka in a spring boot application. In order to learn how to create a spring boot project, r
2 min read
Spring Boot | How to publish JSON messages on Apache KafkaApache Kafka is a publish-subscribe messaging system. A messaging queue lets you send messages between processes, applications, and servers. In this article, we will see how to send JSON messages to Apache Kafka in a spring boot application. In order to learn how to create a spring boot project, ref
4 min read
Spring Boot with AOP
Spring Boot - AOP(Aspect Oriented Programming)The Java applications are developed in multiple layers, to increase security, separate business logic, persistence logic, etc. A typical Java application has three layers namely they are Web layer, the Business layer, and the Data layer. Web layer: This layer is used to provide the services to the e
4 min read
How to Implement AOP in Spring Boot Application?AOP(Aspect Oriented Programming) breaks the full program into different smaller units. In numerous situations, we need to log, and audit the details as well as need to pay importance to declarative transactions, security, caching, etc., Let us see the key terminologies of AOP Aspect: It has a set of
10 min read
Spring Boot - Difference Between AOP and OOPAOP(Aspect-Oriented Programming) complements OOP by enabling modularity of cross-cutting concerns. The Key unit of Modularity(breaking of code into different modules) in Aspect-Oriented Programming is Aspect. one of the major advantages of AOP is that it allows developers to concentrate on business
3 min read
Spring Boot - Difference Between AOP and AspectJSpring Boot is built on the top of the spring and contains all the features of spring. And is becoming a favorite of developers these days because of its rapid production-ready environment which enables the developers to directly focus on the logic instead of struggling with the configuration and se
3 min read
Spring Boot - Cache ProviderThe Spring Framework provides support for transparently adding caching to an application. The Cache provider gives authorization to programmers to configure cache explicitly in an application. It incorporates various cache providers such as EhCache, Redis, Guava, Caffeine, etc. It keeps frequently a
6 min read