You are here
Home > Spring Boot >

How to develop a Reactive CRUD REST API with Spring WebFlux?

Reactive Programming Spring Boot, Spring Webflux with MongoDB Example, Spring Boot Reactive, Reactive REST API, Spring Webflux CRUD Example, How to develop a Reactive CRUD REST API with Spring WebFlux?, Reactive Stack vs Servlet Stack, Spring Reactive Client with WebClient etc.

How to develop a Reactive CRUD REST API with Spring WebFlux?In this article, we will discuss about ”How to develop a Reactive CRUD REST API with Spring WebFlux?”. In other words, we will be talking about a new way of working in REST APIs which is Reactive Programming. No doubt, if we talk about the performance, this way is faster than the traditional way of developing REST. Moreover, Reactive Programming offers us to utilize application resources optimally. We will also discuss how to work with the concept of Spring WebFlux as the part of Reactive Programming and the related concepts in below sections step by step.

Why & When to use Reactive Programming?

In a Spring Boot MVC based web application, every request is internally a thread. This thread may communicate with the database until it gets data in response. This thread remains in blocking mode until it gets a response from the database. Also, this thread can’t be assigned to any other request while it is in blocking mode. Reactive Programming ensures application resource utilization optimally instead of keeping threads in idle mode. It makes resource utilization accurately by implementing an event loop.

When a thread makes database call, the call is handed over to event loop to process the SQL Query and thread becomes free for that duration. Now the thread in its free duration can process the other request parallelly. Subsequently, either same thread or another thread proceeds to serve the response. In our article ‘How to develop a Reactive CRUD REST API with Spring WebFlux?’ we will discuss more than this.

To get the benefits of Spring Boot Reactive Programming, at server side, we can use Spring Web Flux. Also at DB side, we can use Spring Boot Reactive Database such as Mongo DB. As of now it has direct support of only NoSQL DB such as MongoDB and many more. Moreover, Spring Reactive is recommended instead of Spring REST. We will develop a Spring Webflux CRUD example to understand most of the concepts of Webflux. Let’s start discussing all about our topic ‘How to develop a Reactive CRUD REST API with Spring WebFlux?’ in detail.

What Can You Expect from This Article?

In summary, you will be able to develop a REST producer API and the respective consumer API using Spring WebFlux in a single article itself. Once you complete going through all sections of this article, you will be able to answer :

1) What are the benefits of using Reactive Programming?
2) What does Reactive mean in Programming world?
3) What is Spring WebFlux?
4) Why Spring WebFlux?
5) What is the difference between Reactive Stack & Servlet Stack?
6) Minimum Software requited to support Reactive?
7) How to integrate with database in Reactive?
8) What is R2DBC?
9) Of course ‘How to develop a Reactive CRUD REST API with Spring WebFlux?’
10) Hands-on of spring webflux crud example
11) Furthermore, How to develop/build a Reactive Client/Consumer Application using WebClient?

What is Reactive in programming world?

Let’s consider the term non-blocking. Non-blocking is reactive as instead of being blocked, it meant for reacting to notifications as soon as previous operations complete or data become available. In fact the term, “reactive,” refers to programming models that are built around reacting to change such as UI controllers reacting to mouse events or network components reacting to I/O events etc.

What is Spring WebFlux? 

The primary web framework included in the Spring Framework, Spring Web MVC, internally uses the Servlet API and Servlet containers. Similarly to support the reactive-stack web framework, Spring WebFlux, was added later in Spring 5.0. It runs on servers such as Netty, Undertow, and Servlet 3.1+ containers and is fully non-blocking. Both frameworks have homogeneous names of their source modules: spring-webmvc and spring-webflux respectively. Applications can use either module. Sometimes both such as Spring MVC Controllers with the reactive WebClient  becomes the perfect combination.

Why was Spring WebFlux created?

There was a need of framework that can handle concurrency with a minimum number of threads, scale with minimum hardware resources and can also support non-blocking web stack. In other words, there was a need of reactive-stack web framework. Apart from that there was a need to promote functional programming. Needless to say, lambda expressions in Java 8 created opportunities for functional programming in Java. Also programmatically, Java 8 enabled Spring WebFlux to provide functional web endpoints with annotated controllers.

What is the difference between Reactive Stack and Servlet Stack?

Servlet Stack Reactive Stack
Spring's web application module is spring-webmvcSpring's web application module is spring-webflux
Spring MVC based on the Servlet API Spring WebFlux based on the ground to take advantage of multicore, next generation processors
Uses a synchronous blocking I/O architectureIs a non-blocking framework
Works on the principle of one request per thread model.Has capability to handle massive number of concurrent connections.
By default uses Servlet ContainersBy default uses Servlet 3.1+ Containers and Netty
Uses Spring Data Repositories as JDBC, JPA, NoSQLUses Spring Data Reactive Repositories as Mongo, Cassandra, Redis, Couchbase, R2DBC
Programming model uses Servlet APIProgramming model uses Reactive Streams Adapters
Spring's Security module is Spring Security ReactiveSpring's Security module is Spring Security

What is minimum Software required to support Reactive?

♦ Spring 5.x to support Spring Web Flux
♥ Servlets 3.1+
♦ Spring Boot uses Netty Server by default as it is well-established in the asynchronous, non-blocking space.

How database integration happens in Reactive way?

Accessing and processing data via database in a reactive way is also equally important. NoSQL databases such as MongoDB, Redis, and Cassandra all have native reactive support as part of Spring Data. Moreover, many relational databases such as Microsoft SQL Server, MySQL, H2, Postgres and Google Spanner have reactive support via R2DBC(Reactive Relational Database Connectivity).

What is R2DBC?

R2DBC stands for Reactive Relational Database Connectivity, offers integration of relational databases in a reactive application stack. As of now only NoSQL databases have native reactive support in Spring Data. R2DBC acts as an incubator to integrate relational databases using a reactive driver. Spring Data R2DBC applies popular Spring abstractions and repository support for R2DBC. It offers an easier way to build Spring-based applications that use relational databases such as Microsoft SQL Server, MySQL, Postgres, H2 etc. in a reactive application stack.

How to develop a Reactive CRUD REST API with Spring WebFlux?

To illustrate the actual reactive programming, we will develop a spring webflux crud example. Needless to say, CRUD is nothing but an abbreviation for Create, Retrieve, Update & Delete operations. Here we will consider ‘Invoice’ as an entity to develop the API. Let’s start our exercise by following step by step instructions.

Software/Tools used in this Project ?

♦ STS (Spring Tool Suite) : Version-> 4.7.1.RELEASE
⇒ Dependent Starters : ‘Spring Reactive Web’, ‘Spring Data Reactive Mongo DB’, ‘Lombok’ and ‘Spring Boot DevTools’
♥ MongoDB 3.6.20 2008R2Plus SSL (64 bit)
♦ JDK8 or later versions (Extremely tested on JDK8, JDK11 and JDK14)

Step#1: Create Project using STS(Spring Tool Suite)

If you are new to Spring Boot, visit Internal Link to create a sample project in spring boot. While creating starter project in STS, select starter dependencies as  ‘Spring Reactive Web’, ‘Spring Data Reactive Mongo DB’, and ‘Lombok’. You can also add ‘Spring Boot DevTools’ optionally.

If you are new to ‘Lombok’, kindly visit ‘How to configure Lombok‘ and to know all about it in detail. Please note that we are using Mongo DB as database because reactive stack has direct support of only NoSQL databases. If you still have not installed Mongo DB in your system, follow the instructions to install it from here. To get an easy grasp on ‘How to work with Mongo DB’, please visit Mogo DB tutorial.

Step#2 : Update database properties in application.properties file

Update application.properties to connect with Mongo DB accordingly as below.

# application.properties
----------------------------------------
spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
spring.data.mongodb.database=reactivedb

Step#3 : Create Invoice Entity & Repository interface

Now create Invoice.java and InvoiceRepositoty.java as below. InvoiceRepository.java will be an interface which will extend ReactiveMongoRepository<Invoice, Integer>.

// Invoice.java
----------------------------------------------------------------
package com.dev.springboot.reactive.model;

import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import lombok.Data;

@Data
@Document
public class Invoice {

    @Id
    private Integer id;
    private String name;
    private String number;
    private Double amount;
}
// InvoiceRepository.java
------------------------------------------------------------------------------------
package com.dev.springboot.reactive.repo;

import org.springframework.data.mongodb.repository.ReactiveMongoRepository;
import com.dev.springboot.reactive.model.Invoice;

public interface InvoiceRepository extends ReactiveMongoRepository<Invoice, Integer> {

}

Step#4 : Create Service Interface & Service Implementation class

Create Service Interface and Service Impl class as IInvoiceService.java and InvoiceServiceImpl.java accordingly as shown below. Please observe the usage of Mono & Flux in service methods. Use Mono for single object and Flux for multiple objects as return type.

IInvoiceService.java
package com.dev.springboot.reactive.service;

import com.dev.springboot.reactive.model.Invoice;

import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

public interface IInvoiceService {

	public Mono<Invoice> saveInvoice(Invoice invoice);
	
	public Flux<Invoice> findAllInvoices();
	
	public Mono<Invoice> getOneInvoice(Integer id);
	
	public Mono<Void> deleteInvoice(Integer id);
}
InvoiceServiceImpl.java
package com.dev.springboot.reactive.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.dev.springboot.reactive.model.Invoice;
import com.dev.springboot.reactive.repo.InvoiceRepository;

import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

@Service
public class InvoiceServiceImpl implements IInvoiceService {

	@Autowired
	private InvoiceRepository repo;
	
	public Mono<Invoice> saveInvoice(Invoice invoice){
		return repo.save(invoice);
		//for Mono<String> return type
		 //return Mono.just("saved successfully");
	}
	
	public Flux<Invoice> findAllInvoices(){
		//return repo.findAll();
		return repo.findAll().switchIfEmpty(Flux.empty());
	}
	
	public Mono<Invoice> getOneInvoice(Integer id){
		return repo.findById(id).switchIfEmpty(Mono.empty());
	}
	
	public Mono<Void> deleteInvoice(Integer id){
		return repo.deleteById(id);
	}
}

Step#5 : Create InvoiceController class 

Subsequently, write a RestController for Invoice as ‘InvoiceController.java’ as below.

InvoiceRestController.java
package com.dev.springboot.reactive.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.dev.springboot.reactive.model.Invoice;
import com.dev.springboot.reactive.service.IInvoiceService;

import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

@RestController
@RequestMapping("/invoice")
public class InvoiceRestController {

	@Autowired
	private IInvoiceService service;
	
	@PostMapping("/save")
	public Mono<Invoice> saveOneInvoice(@RequestBody Invoice invoice){
		return service.saveInvoice(invoice);
				// for Mono<String>
				// service.saveInvoice(invoice);
				// return Mono.just("Invoice saved" + invoice.getId());
	}
	
	@GetMapping("/allInvoices")
	public Flux<Invoice> getAllInvoices(){
		return service.findAllInvoices();
	}
	
	@GetMapping("/get/{id}")
	public Mono<Invoice> getOneInvoice(@PathVariable Integer id){
		Mono<Invoice> invoice= service.getOneInvoice(id);
		return invoice;
	}
	
	@DeleteMapping("/delete/{id}")
	public Mono<String> deleteInvoice(@PathVariable Integer id){
		service.deleteInvoice(id);
		return Mono.just("Invoice with id: " +id+ " deleted !");
	}
}

How to test created Reactive REST API?

Before testing the created REST API, start your Mongo DB instance. Now you can use the most popular POSTMAN tool to test your API. However, we are going to develop a Reactive Consumer application using WebClient in the next section. If you can wait until then, you will also get knowledge of Reactive Consumer App. Even if you are new to POSTMAN tool, kindly visit our internal article on ‘How to test REST API with POSTMAN.

How to develop a Reactive Client Application with WebClient?

As we already know, for non-reactive REST producer(Servlet Stack REST producer), we generally use RestTemplate in order to develop a consumer. Please also note that Client Application or Consumer Application both we use in the same sense. Here in place of RestTemplate we will use WebClient that supports making request to Reactive RestController and gets final Data either as Mono or as Flux. Moreover WebClient is an interface (DefaultWebClient is an impl class)
that is used to define Reactive Client Application.

Guidelines to develop Reactive Client Application with WebClient

Please follow below guidelines to create a Client application using WebClient.

  1. Create WebClient Object using Base URL.
  2. Provide Path at Controller method using Request METHOD(GET/POST)
  3. Provide Inputs if exist (Body, Params)
  4. Create Request for data retrieval with Type mono/flux

Note : Model class must exist exactly same as in Producer Application.

Step#1: Create Project using STS(Spring Tool Suite)

Create one Spring Boot Starter Project as SpringBoot2ReactiveClientApp. While creating starter project in STS, select starter dependencies as ‘Spring Reactive Web’ and ‘Lombok’. You can also add ‘Spring Boot DevTools’ optionally. If you are new to ‘Lombok’, kindly visit ‘How to configure Lombok‘ and to know all about it in detail.

Step#2 : Update server properties in application.properties file

You need to update the server port and it should be different from the producer application’s server port as you might be running both applications from the same system. Update it something like below.

server.port=9090

Step#3: Create Model class Invoice.java

Please make sure this model class must be the same as it is in the producer application particularly in terms of fields and their datatypes.

Invoice.java
package com.dev.springboot.reactive.model;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;

@Data
@AllArgsConstructor
@RequiredArgsConstructor
public class Invoice {
    
	private Integer id;
	@NonNull
	private String name;
	@NonNull
	private String number;
	@NonNull
	private Double amount;
}

Now its time to really test the API and get the results accordingly. Here we are using Runner classes to test each method in a separate Runner class as in step#4 to step#7. The best way to test and get correct results is that keep @Component at one Runner class at a time and comment it on others which are not part of your current testing.

Step#4: Runner class to fetch/retrieve all Invoices

GetAllInvoicesRunner.java
package com.dev.springboot.reactive.runner;

import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.client.WebClient;

import com.dev.springboot.reactive.model.Invoice;

import reactor.core.publisher.Flux;

@Component
public class GetAllInvoicesRunner implements CommandLineRunner {

	@Override
	public void run(String... args) throws Exception {
		
		WebClient client = WebClient.create("http://localhost:8080");
		Flux<Invoice> flux= client
				.get()
				.uri("/invoice/allInvoices")
				.retrieve()
				.bodyToFlux(Invoice.class);
		flux.doOnNext(System.out::println).blockLast();
	}

}

Step#5: Runner class to fetch/retrieve one Invoice

GetOneInvoiceRunner.java
package com.dev.springboot.reactive.runner;

import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.client.WebClient;

import com.dev.springboot.reactive.model.Invoice;

import reactor.core.publisher.Mono;

@Component
public class GetOneInvoiceRunner implements CommandLineRunner {

	@Override
	public void run(String... args) throws Exception {
		
		WebClient client = WebClient.create("http://localhost:8080");
		Mono<Invoice> mono= client
				.get()
				.uri("/invoice/get/3")
				.retrieve()
				.bodyToMono(Invoice.class);
		mono.subscribe(System.out::println);
	}

}

Step#6: Runner class to save or update Invoice

SavrOrUpdateInvoiceRunner.java
package com.dev.springboot.reactive.runner;

import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.client.WebClient;

import com.dev.springboot.reactive.model.Invoice;

import reactor.core.publisher.Mono;

@Component
public class SavrOrUpdateInvoiceRunner implements CommandLineRunner {

	@Override
	public void run(String... args) throws Exception {
		
		WebClient client = WebClient.create("http://localhost:8080");
		Mono<Invoice> mono= client
				.post()
				.uri("/invoice/save")
				.body(Mono.just(new Invoice(1, "Invoice1", "INV001", 2345.75)),Invoice.class)
				.retrieve().bodyToMono(Invoice.class);
		mono.subscribe(System.out::println);
	}

}

Step#7: Runner class to delete Invoice

DeleteInvoiceRunner.java
package com.dev.springboot.reactive.runner;

import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.client.WebClient;

import reactor.core.publisher.Mono;

@Component
public class DeleteInvoiceRunner implements CommandLineRunner {

	@Override
	public void run(String... args) throws Exception {
		
		WebClient client = WebClient.create("http://localhost:8080");
		Mono<Void> mono= client
				.delete()
				.uri("/invoice/delete/3")
				.retrieve()
				.bodyToMono(Void.class);
		mono.subscribe(System.out::println);
		System.out.println("Invoice Deleted!");
	}

}

Conclusion

After going through all the theoretical and spring webflux crud example part of ‘How to develop a Reactive CRUD REST API with Spring WebFlux?’, finally, we should be able to develop a Reactive CRUD REST API as a producer application with Spring WebFlux in a Spring Boot project. Also, we should be able to develop a Consumer/Client Application using WebClient. Similarly, we expect from you to further extend these examples. Also try to implement them in your project accordingly. In addition, If there is any update in the future, we will also update the article accordingly. Moreover, Feel free to provide your comments in the comments section below.

close

3 thoughts on “How to develop a Reactive CRUD REST API with Spring WebFlux?

Leave a Reply

Top