Spring WebFlux: Reactive HTTP Services

Reading Time: 3 minutes

In this blog, we’ll look at how Spring Webflux supports the creation of HTTP-centric reactive services. Centric, because we will look at the concerns that arise from HTTP-based applications
typical of web applications including but not limited to WebSockets, REST, and more.

How HTTP Works

HTTP is a fairly simple protocol. It has one purpose, and that is to support document retrieval. It supports the request-response interaction model but does not support any application layer flow control mechanism. In HTTP, requests are sent to the server, which then responds with a response.

What are HTTP Requests

An HTTP request message begins with an off character on a leading line that contains an HTTP verb (such as PUT, POST, GET, OPTIONS, and DELETE), destination URI, and HTTP version. The header then follows the starting line. The header is key-value pairs (separated by: and space) that live on different lines. They don’t have HTTP responses some headers (such as Host, User-Agent, and Accept*) are otherwise included in HTTP requests.

Two line breaks follow the headings. Finally, an HTTP request can have an HTTP body. The HTTP body can contain one single source, such as a JSON document. It can also contain multiple sources, called multipart bodies, each of which contains different information. HTML forms usually have multipart bodies.

What are HTTP Responses

The initial line of an HTTP response is called the status line. Contains a version of the HTTP protocol, a
status code, and status text.

There are many common status codes like 200 (“OK”), 201 (“CREATED”), 404 (“ERROR”/”NOT FOUND”), 401 (“UNAUTHORIZED”) and 302 (“FOUND”).

The status text is a description of the status code to help a human being understand the HTTP message.

Next come the HTTP headers, which look the same as the headers in the request.

Finally comes the body option. A web server can send a response with the body at once in a single feed of known length, or it can send a response as a single feed of unknown length, encoded in blocks with Transfer-Encoding set to chunked or as a multipart body.

Spring WebFlux: Reactive Web Runtime

Spring MVC builds on the Servlet specification. A default setting in the servlet specification
blocks threads that things are synchronous. The servlet specification runs on assumption that the requests block threads or that the requests are short-lived interactions that do not require asynchronous I/O. If you want asynchronous I/O, it is possible to get it, but it is not the default and is relatively limited.

Spring Framework 5 introduced a new network reactive web runtime based on Netty and a framework, both called Spring WebFlux, and assumes the presence of Java 8 and lambdas.

Spring Webflux assumes that everything is asynchronous by default. This has interesting consequences
to the fact that everything in Spring Webflux is reactive by default. If you want to return simple JSON
stanza with eight records, you return a Publisher.

Simple enough. If you want to do something long-lived, such as WebSockets or server-sent events, for which asynchronous I/O is a better choice, use Publisher too.

Sample

Let’s introduce a sample domain entity, Customer, and a supporting repository, CustomerRepository. Let’s suppose we have an entity, Customer, with two fields, id, and name:

Customer Entity

import lombok.Data;

import lombok.NoArgsConstructor;

@Data

@NoArgsConstructor

class Customer {


private String id, name;


Customer(String i, String n) {

this.id = i;

this.name = n;

}


Customer(String name) {

this.name = name;

}


}

Customer Repository

import org.springframework.stereotype.Component;

import org.springframework.stereotype.Repository;

import reactor.core.publisher.Flux;

import reactor.core.publisher.Mono;

import java.util.Map;

import java.util.UUID;

import java.util.concurrent.ConcurrentHashMap;


@Repository

public class CustomerRepository {


private final Map data = new ConcurrentHashMap<>();


Mono findById(String id) {

return Mono.just(this.data.get(id));

}


Mono save(Customer customer) {

var uuid = UUID.randomUUID().toString();

this.data.put(uuid, new Customer(uuid, customer.getName()));

return Mono.just(this.data.get(uuid));

}


Flux findAll() {

return Flux.fromIterable(this.data.values());

}


}

Rest Controller

import org.springframework.http.ResponseEntity;

import org.springframework.web.bind.annotation.*;

import reactor.core.publisher.Flux;

import reactor.core.publisher.Mono;

import java.net.URI;


@RestController

@RequestMapping(value = "/rc/customers")

class CustomerRestController {


private final CustomerRepository repository;


CustomerRestController(CustomerRepository cr) {

this.repository = cr;

}


@GetMapping("/{id}")

Mono<Customer> byId(@PathVariable("id") String id) {

return this.repository.findById(id);

}


@GetMapping

Flux<Customer> all() {

return this.repository.findAll();

}


@PostMapping

Mono<ResponseEntity<?>> create(@RequestBody Customer customer) {

return this.repository.save(customer)//

.map(customerEntity -> ResponseEntity//

.created(URI.create("/rc/customers/" + customerEntity.getId()))

//

.build());

}
}

Reference: https://docs.spring.io/spring-framework/docs/current/reference/html/web-reactive.html

Knoldus Blogs: https://blog.knoldus.com/

Written by 

Prakhar is a Software Consultant at Knoldus . He has completed his Masters of Computer Applications from Bharati Vidyapeeth Institute of Computer Applications and Management, Paschim Vihar . He likes problem solving and exploring new technologies .

Leave a Reply