Open In App

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, Delete) operation, we have created one REST API endpoint. These API endpoints are defined by using the RouterFunction. It returns a route function.



Tools and Technologies:

Below are the tools and technologies we have used to create this project.

Project Creation:

Project Folder Structure:

Below we can see the Project Structure.



Project Dependencies:

In this project, we have used below Gradle dependencies.

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'
}

MongoDB Connection

In application.properties file configuration the database connection with required properties. Below we have provided the connection and working is the database name.

spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
spring.data.mongodb.database=working

In project main package, we have created different classes for different purposes. Each Java class perform different actions. Below is the list of all the classes and explanation of their functionally.

Student POJO class

Here, we have created one POJO class which handles the database operations by using lombok dependency.




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

The UserRepo interface (Repository layer) is used for performing the database related operations on Student class.




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 class is a service layer for creating API logic.




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 is another Java class for handling REST API end point.




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 logic is used for creating a new Student row in collection. Here, we have used Mono publisher, and it returns the ServerResponse as an output.

REST API URL: api/student/add




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 the Postman, successfully the data is inserted into a collection. Below we have provided the output image for reference. When we hit this API URL, the data is saved into collection and return that saved record as an output.

Output:

Below we can see that we have added one Student with name and age in POSTMAN.

deleteStudentById REST API:

The API logic is used for deleting an existing student data by using Student Id. If Id is available student data will be deleted, or else, it will give some error message as an output. In this, we have created one flatmap for finding Id. If the id exists, then deleted or switchIfEmpty() method will be executed.

REST API URL: api/student/delete




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:

Below we can see the deleted student id in POSTMAN.

updateStudentById REST API:

This API is used for updating the existing Student data by using the Student ID. If Student Id not found it gives an error message otherwise successfully update new data for existing id, then return the new data as server response.

REST API URL: api/student/update




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:

Below we can see the updated student details in POSTMAN.

getAllStudents REST API:

This REST API returns all existing student data from database.

REST API URL: api/student/update




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 Student details only, when we hit this in POSTMAN, the API return that two records data from database.

Output:

In POSTMAN, we can test the API end point, and we got the below student details.


Article Tags :