Open In App

Building Reactive Microservices with Spring WebFlux

Last Updated : 20 Jun, 2024
Comments
Improve
Suggest changes
Like Article
Like
Report

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:

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.

Application Started


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:

save API Testing


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:

search API Testing


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:

all API Testing


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:

delete API Testing




Next Article

Similar Reads