In this tutorial, you will learn how to build CRUD REST APIs using Spring Boot, Spring WebFlux, and MongoDB NoSQL database.
Before implementing this tutorial, make sure that you have installed MongoDB on your machine and MongoDB instance is running.
You may also be interested in Testing Spring WebFlux Reactive CRUD Rest APIs using WebTestClient.
Spring WebFlux Overview
Spring WebFlux is a non-blocking, reactive web framework for building reactive, scalable web applications. It is part of the Spring Framework, and it is built on top of Project Reactor, which is a reactive programming library for building asynchronous, non-blocking applications.
Spring WebFlux provides support for both server-side and client-side components, and it can be used to build web applications that are reactive and scalable. It supports the creation of RESTful web services and web applications using the functional programming style, and it provides a reactive alternative to the Spring MVC web framework.
Spring WebFlux uses a reactive stream-based model for handling requests and responses, which allows it to handle a high volume of requests with a small number of threads. Overall, Spring WebFlux is a powerful tool for building reactive, scalable web applications, and it is well-suited for use in high-concurrency environments.
Reactive MongoDB Driver
Reactive MongoDB is a driver for MongoDB that is designed to support the Reactive Streams specification. It allows developers to build reactive, non-blocking applications that can work with MongoDB in a more efficient and scalable manner.
The Reactive MongoDB driver is built on top of the MongoDB Java driver, and it provides a reactive API that can be used to perform operations on MongoDB collections. It allows developers to work with MongoDB using a reactive programming model, which allows them to write asynchronous, non-blocking code that can handle a large number of concurrent operations.
Reactive MongoDB supports all the core MongoDB features, including insert, update, delete, and find operations, and it also supports aggregation, map-reduce, and other advanced features. It can be used in conjunction with other reactive libraries, such as Project Reactor or RxJava, to build scalable, reactive applications that can work with MongoDB.
Overall, Reactive MongoDB is a powerful tool for building reactive, scalable applications that can work with MongoDB, and it is well-suited for use in high-concurrency environments.
1. Create Spring Boot Application
Let's create a Spring boot application using Spring Intializr.
Refer to the below screenshot to enter the details while generating the Spring boot project using Spring Intializr:
Note that we are using Spring WebFlux, MongoDB Reactive, and Lombok libraries.
Here is the complete pom.xml file for your reference:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.0.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>net.javaguides</groupId>
<artifactId>springboot-webflux-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot-webflux-demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>17</java.version>
</properties>
<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.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>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
2. Project Structure
Refer to the below screenshot to create the packing or project structure for the application:
3. Configure MongoDB
You can configure MongoDB by simply adding the following property to the application.properties file:
spring.data.mongodb.uri=mongodb://localhost:27017/ems
Spring Boot will read this configuration on startup and automatically configure the data source.
4. Create Domain Class
Let's create an Employee MongoDB document and add the following content to it:
package net.javaguides.springbootwebfluxdemo.entity;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Document(value = "employees")
public class Employee {
@Id
private String id;
private String firstName;
private String lastName;
private String email;
}
Note that we have given MongoDB collection name - employees.
5. Creating Repository - EmployeeRepository
Next, we’re going to create the data access layer which will be used to access the MongoDB database.
Let's create an EmployeeRepository interface and add the following content to it:
package net.javaguides.springbootwebfluxdemo.repository;
import net.javaguides.springbootwebfluxdemo.entity.Employee;
import org.springframework.data.repository.reactive.ReactiveCrudRepository;
public interface EmployeeRepository extends ReactiveCrudRepository<Employee, String> {
}
The EmployeeRepository interface extends from ReactiveMongoRepository which exposes various CRUD methods on the Document. Spring Boot automatically plugs in an implementation of this interface called SimpleReactiveMongoRepository at runtime.
So you get all the CRUD methods on the Document readily available to you without needing to write any code.
6. Create EmployeeMapper - Map Entity to Dto and Vice Versa
Let's create EmployeeMapper class to map an entity to Dto and vice versa:
package net.javaguides.springbootwebfluxdemo.mapper;
import net.javaguides.springbootwebfluxdemo.dto.EmployeeDto;
import net.javaguides.springbootwebfluxdemo.entity.Employee;
public class EmployeeMapper {
public static EmployeeDto mapToEmployeeDto(Employee employee){
return new EmployeeDto(
employee.getId(),
employee.getFirstName(),
employee.getLastName(),
employee.getEmail()
);
}
public static Employee mapToEmployee(EmployeeDto employeeDto){
return new Employee(
employeeDto.getId(),
employeeDto.getFirstName(),
employeeDto.getLastName(),
employeeDto.getEmail()
);
}
}
7. Create Service Layer
EmployeeService Interface
Let's create an EmployeeService interface and add below CRUD methods to it:
package net.javaguides.springbootwebfluxdemo.service;
import net.javaguides.springbootwebfluxdemo.dto.EmployeeDto;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
public interface EmployeeService {
Mono<EmployeeDto> saveEmployee(EmployeeDto employeeDto);
Mono<EmployeeDto> getEmployee(String employeeId);
Flux<EmployeeDto> getAllEmployees();
Mono<EmployeeDto> updateEmployee(EmployeeDto employeeDto, String employeeId);
Mono<Void> deleteEmployee(String employeeId);
}
EmployeeServiceImpl class
Let's create EmployeeServiceImpl class that implements the EmployeeService interface and its methods:
package net.javaguides.springbootwebfluxdemo.service.impl;
import lombok.AllArgsConstructor;
import net.javaguides.springbootwebfluxdemo.dto.EmployeeDto;
import net.javaguides.springbootwebfluxdemo.entity.Employee;
import net.javaguides.springbootwebfluxdemo.mapper.EmployeeMapper;
import net.javaguides.springbootwebfluxdemo.repository.EmployeeRepository;
import net.javaguides.springbootwebfluxdemo.service.EmployeeService;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@Service
@AllArgsConstructor
public class EmployeeServiceImpl implements EmployeeService {
private EmployeeRepository employeeRepository;
@Override
public Mono<EmployeeDto> saveEmployee(EmployeeDto employeeDto) {
Employee employee = EmployeeMapper.mapToEmployee(employeeDto);
Mono<Employee> savedEmployee = employeeRepository.save(employee);
return savedEmployee
.map((employeeEntity) -> EmployeeMapper.mapToEmployeeDto(employeeEntity));
}
@Override
public Mono<EmployeeDto> getEmployee(String employeeId) {
Mono<Employee> employeeMono = employeeRepository.findById(employeeId);
return employeeMono.map((employee -> EmployeeMapper.mapToEmployeeDto(employee)));
}
@Override
public Flux<EmployeeDto> getAllEmployees() {
Flux<Employee> employeeFlux = employeeRepository.findAll();
return employeeFlux
.map((employee) -> EmployeeMapper.mapToEmployeeDto(employee))
.switchIfEmpty(Flux.empty());
}
@Override
public Mono<EmployeeDto> updateEmployee(EmployeeDto employeeDto, String employeeId) {
Mono<Employee> employeeMono = employeeRepository.findById(employeeId);
return employeeMono.flatMap((existingEmployee) -> {
existingEmployee.setFirstName(employeeDto.getFirstName());
existingEmployee.setLastName(employeeDto.getLastName());
existingEmployee.setEmail(employeeDto.getEmail());
return employeeRepository.save(existingEmployee);
}).map((employee -> EmployeeMapper.mapToEmployeeDto(employee)));
}
@Override
public Mono<Void> deleteEmployee(String employeeId) {
return employeeRepository.deleteById(employeeId);
}
}
8. Create Controller Layer - Reactive REST APIs
Let’s write the APIs that will be exposed to the clients. Let's create an EmployeeController with the following contents:
package net.javaguides.springbootwebfluxdemo.controller;
import lombok.AllArgsConstructor;
import net.javaguides.springbootwebfluxdemo.dto.EmployeeDto;
import net.javaguides.springbootwebfluxdemo.service.EmployeeService;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@RestController
@RequestMapping("api/employees")
@AllArgsConstructor
public class EmployeeController {
private EmployeeService employeeService;
@PostMapping
@ResponseStatus(value = HttpStatus.CREATED)
public Mono<EmployeeDto> saveEmployee(@RequestBody EmployeeDto employeeDto){
return employeeService.saveEmployee(employeeDto);
}
@GetMapping("{id}")
public Mono<EmployeeDto> getEmployee(@PathVariable("id") String employeeId){
return employeeService.getEmployee(employeeId);
}
@GetMapping
public Flux<EmployeeDto> getAllEmployees(){
return employeeService.getAllEmployees();
}
@PutMapping("{id}")
public Mono<EmployeeDto> updateEmployee(@RequestBody EmployeeDto employeeDto,
@PathVariable("id") String employeeId){
return employeeService.updateEmployee(employeeDto, employeeId);
}
@DeleteMapping("{id}")
@ResponseStatus(value = HttpStatus.NO_CONTENT)
public Mono<Void> deleteEmployee(@PathVariable("id") String employeeId){
return employeeService.deleteEmployee(employeeId);
}
}
Note that all the controller endpoints return a Publisher in the form of a Flux or a Mono.
Testing Reactive CRUD REST APIs using Postman Client
Create Employee REST API:
Get Employee REST API:
Get All Employees REST API:
Update Employee REST API:
Delete Employee REST API:
Conclusion
In this tutorial, you learned how to build CRUD REST APIs using Spring Boot, Spring WebFlux, and MongoDB NoSQL database.
Check out all the Spring Boot tutorials at https://www.javaguides.net/p/spring-boot-tutorial.html
Comments
Post a Comment
Leave Comment