Building Reactive Microservices with Spring WebFlux
Last Updated :
20 Jun, 2024
This article will teach us how to build reactive microservices with Spring WebFlux using a related example. Here, we create a student microservice to handle students and their data. For understanding purposes, we provide basic features and functionalities such as adding a student, searching for a student, deleting a student, and getting all student data.
Student Microservice Functionalities
- Add Student: For adding new student data we need to provide the name and age of the student.
- Delete Student: If you want to delete a student you need a student ID then only you can delete otherwise you will get a Not Student ID found.
- Search Student Data: If you want to search a student's details you need a student ID then only you can search student data otherwise you will get No Student ID found.
- Get All Students data: We can get all the existing student data.
Prerequisites:
- Spring Framework
- Spring WebFlux
- Error Handling in Spring WebFlux
- Spring Annotations
- Components & Beans in Spring Framework
- Java Programming
Tools & Technologies:
- Spring Tool Suite
- Spring Framework
- Reactive programming
- Maven
- MongoDB
Steps to Build Reactive Microservice with Spring WebFlux
Here, we created one simple spring reactive project by using spring initializr. Below, we have provided the dependencies which are used in this Spring Application.
Project dependencies:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb-reactive</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
Project Folder Structure:

Step 1: Create a Spring Starter Project
Once Project creation is completed then connect with the database. Here, we use MongoDB and below we have provided the connection details.
Database Connection:
spring.application.name=microservices
spring.data.mongodb.host=localhost
spring.data.mongodb.database=studentdb
spring.data.mongodb.port=27017
Step 2: Create Entity Class
After that, we created a Student Entity class which is used for data handling while performing the database related operations.
- Here, we use lombok dependency for setters and getters and constructors creation.
- After this, we define the collection name by using @document annotation.
- Then we define the required student fields.
Student Data:
- Id
- Student Name
- Student Age
Student.java:
Java
package com.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 = "students")
public class Student {
@Id
private String id;
private String name;
private String age;
}
Step 3: Create Repository
Here, we created a Repository class by using @Repository annotation by using a interface named StudentRepo and it is extends to ReactiveMongoRepository.
This will take entity class and data type of that entity class as input arguments. This repository is used for performing database related operations in Student microservice.
StudentRepo.java:
Java
package com.app;
import org.springframework.data.mongodb.repository.ReactiveMongoRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface StudentRepo extends ReactiveMongoRepository<Student, String>{
}
Step 4: Create Service Class
Here, we created a student handler by using @Service annotation.
- After that, we autowired required classes by using @Autowired annotation.
- Here, we write required logic for add student, delete student, search student details and get all student data by using Mono publisher help.
Below we provide the java code for your reference.
StudentHandler.java:
Java
package com.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 StudentHandler {
@Autowired
private StudentRepo repo;
public Mono<ServerResponse> saveStudent(ServerRequest request) {
return request.bodyToMono(Student.class).flatMap(data -> {
return repo.save(data).flatMap(done -> {
return ServerResponse.ok().bodyValue("Student Saved Successfully \n" + data);
});
});
}
public Mono<ServerResponse> findStudent(ServerRequest request) {
return request.bodyToMono(Student.class).flatMap(data -> {
return repo.findById(data.getId()).flatMap(done -> {
return ServerResponse.ok().bodyValue(done);
});
}).onErrorResume(e -> {
return ServerResponse.badRequest().bodyValue("Student ID Not Found");
});
}
public Mono<ServerResponse> findAll(ServerRequest request) {
return repo.findAll().collectList().flatMap(done -> ServerResponse.ok().bodyValue(done))
.onErrorResume(e -> ServerResponse.badRequest().bodyValue("No Data Found"));
}
public Mono<ServerResponse> deleteStudent(ServerRequest request) {
return request.bodyToMono(Student.class).flatMap(data -> {
return repo.deleteById(data.getId()).then(ServerResponse.ok().bodyValue("Student Details Deleted"))
.onErrorResume(e -> ServerResponse.badRequest().bodyValue("Student ID Not Found"));
});
}
}
Step 5: Create Router Function
Here, we created RouterFunction which is used for define the API endpoints.
RouterConfig.java:
Java
package com.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 RouterConfig {
@Autowired
private StudentHandler handler;
@Bean
RouterFunction<ServerResponse> router(){
return RouterFunctions.route(RequestPredicates.POST("/save"), handler::saveStudent)
.andRoute(RequestPredicates.POST("/search"), handler::findStudent)
.andRoute(RequestPredicates.POST("/all"), handler::findAll)
.andRoute(RequestPredicates.POST("/delete"), handler::deleteStudent)
;
}
}
Step 6: Run the Application
Once development is completed, then run this project as Spring Boot App. By default, the project is running on port number 8080 with Netty server.

APIs Information
Once project successfully running, then test the APIs. Here we use Postman tool for API testing.
Save Student API:
http://localhost:8080/save
This API is used for save the student student details by using post mapping.
public Mono<ServerResponse> saveStudent(ServerRequest request) {
return request.bodyToMono(Student.class).flatMap(data -> {
return repo.save(data).flatMap(done -> {
return ServerResponse.ok().bodyValue("Student Saved Successfully \n" + data);
});
});
}
Output:

Search Student API:
http://localhost:8080/search
This API is used for search student details by using Student id. Otherwise, it will throw Not Found.
public Mono<ServerResponse> findStudent(ServerRequest request) {
return request.bodyToMono(Student.class).flatMap(data -> {
return repo.findById(data.getId()).flatMap(done -> {
return ServerResponse.ok().bodyValue(done);
});
}).onErrorResume(e -> {
return ServerResponse.badRequest().bodyValue("Student ID Not Found");
});
}
Output:

Get All API:
This API is used for display the all existing data in the database.
http://localhost:8080/all
public Mono<ServerResponse> findAll(ServerRequest request) {
return repo.findAll().collectList().flatMap(done -> ServerResponse.ok().bodyValue(done))
.onErrorResume(e -> ServerResponse.badRequest().bodyValue("No Data Found"));
}
Output:

Delete Student API:
This API is used for delete a existing student data with help of Student ID.
http://localhost:8080/delete
public Mono<ServerResponse> deleteStudent(ServerRequest request) {
return request.bodyToMono(Student.class).flatMap(data -> {
return repo.deleteById(data.getId()).then(ServerResponse.ok().bodyValue("Student Details Deleted"))
.onErrorResume(e -> ServerResponse.badRequest().bodyValue("Student ID Not Found"));
});
}
Output:

Similar Reads
Non-Blocking I/O Operation with Spring WebFlux
Spring WebFlux is most powerful framework for building reactive, non-blocking web applications. Unlike the traditional Spring MVC which can be based on the synchronous, blocking the I/O model, Spring WebFlux the reactor library enables asynchronous and nonblocking operations. It can allow for better
5 min read
Best Practices to Secure Microservices with Spring Security
Microservices architecture is an approach to software development where an application is broken down into smaller, independent services that can be developed, deployed, and scaled independently of one another. Each service is designed to perform a specific task or function and communicates with oth
6 min read
Spring Boot Microservices Communication using RestTemplate with Example
RestTemplate is a synchronous REST client which performs HTTP requests using a simple template-style API. We can also state that RestTemplate class is a synchronous client and is designed to call REST services. Apart from that, RestTemplate class plays a major role whenever we talk about Spring Boot
14 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
Rate Limiting in Spring WebFlux
Rate limiting is a crucial technique to control the amount of incoming traffic to the server. This prevents abuse, ensures fair resource usage, and protects against potential Denial of Service (DOS) attacks. In the Spring WebFlux, rate limiting can be implemented effectively using the Spring Cloud G
5 min read
Spring Boot Microservices Communication using WebClient with Example
WebClient is an interface illustrating the main entry point for performing web requests. It is also known as the reactive web client which is introduced in Spring 5. This new client is a reactive, non-blocking solution that works over the HTTP/1.1 protocol. We can also say that it is a replacement f
14 min read
Resilient Microservices Design
Resilient Microservices Design explores creating tough, adaptable systems from small, independent parts. Imagine a city's infrastructure, each building operates independently, yet collaborates seamlessly. Similarly, microservices are like small city blocks, each serving a specific purpose. This arti
8 min read
Spring WebFlux Application Integration with Reactive Messaging System Kafka
Spring WebFlux is the framework for building reactive applications on the JVM. It is useful for reactive programming and makes it easier to build asynchronous, non-blocking and event-driven applications. Apache Kafka is a distributed streaming platform which allows us to publish and subscribe to str
5 min read
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
Microservices Communication with NATS
Microservices architectures enable the development of scalable and independent services within the system, promoting agility and robustness. Communication between these services is crucial for the overall performance and functionality of the application. NATS is a high-performance messaging system t
6 min read