How to use Spring WebClient to invoke REST services reactively and non reactively?

Let’s say you want to invoke a reactive REST service developed using Spring WebFlux.

A reactive REST service is one which lets you invoke itself asynchronously.

You either get a Mono response (for a single object response) or a Flux response (for multiple objects).

Here is a demo of how to call a reactive REST service for GET and POST operations.

I created two REST services one which returns a list of employees stored in my local MongoDB database( MongoDB allows data to be returned reactively) and another to store an employee, both using Spring WebFlux . Both of them are running on localhost:8080.

Here is how to consume a GET request reactively using Spring WebClient:

First include the Spring Reactive Web dependency in your pom.xml :

                <dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-webflux</artifactId>
		</dependency>

Then use a similar code as below to consume GET REST service:

                WebClient webClient = WebClient.create("http://localhost:8080");

		Flux<Map> employeeMap = webClient.
				get().uri("/getAllEmployees").
				retrieve().bodyToFlux(Map.class);


		employeeMap.subscribe(response -> System.out.println(response));

As you see , you first create a WebClient using the create() static method by passing the base URL.

Then call get() method on the webClient and keep on adding your inputs in fluent API style: the relative url for getting employees , the method retrieve() to make the actual call and the method bodyToFlux() to convert the response to a flux object .

Once you receive the flux object , subscribe to it.

Inside the subscription fetch the response (In the above case I am printing them to the console).

Here is the output I got:

{id=5ee3506a4ccb93b1011ba07c, name=Roy, age=30, technology=angular}
{id=5ee4deac56004ae5298e0d84, name=Vijay, age=32, technology=Java}
{id=5ee4ed1f50e08701b9185ea2, name=Rithika, age=26, technology=Java}
{id=5ee72b3fd5929a1c5a0af3f4, name=Rathika, age=24, technology=MongoDB}
{id=5ee72ba3d5929a1c5a0af3f5, name=Kajal, age=23, technology=Angular}
{id=5ee7335fd5929a1c5a0af3f6, name=Gayathri, age=31, technology=MySQL}
{id=5ee733f2d5929a1c5a0af3f7, name=Megala, age=34, technology=Java}

The above example is an asynchronous call and the call will not be made until you subscribe to the Flux object.

You can also receive response synchronously using Spring WebClient. Spring might soon retire Rest Template module and we might start using WebClient for making blocking calls as well.

To do this , instead of subscribing to the flux object convert it to a list and call block() method on it:

List<Map> output = employeeMap.collectList().block();

The response is a collection of maps each representing an employee.

Here is the output on printing the above output object:

[{id=5ee3506a4ccb93b1011ba07c, name=Roy, age=30, technology=angular}, {id=5ee4deac56004ae5298e0d84, name=Vijay, age=32, technology=Java}, {id=5ee4ed1f50e08701b9185ea2, name=Rithika, age=26, technology=Java}, {id=5ee72b3fd5929a1c5a0af3f4, name=Rathika, age=24, technology=MongoDB}, {id=5ee72ba3d5929a1c5a0af3f5, name=Kajal, age=23, technology=Angular}, {id=5ee7335fd5929a1c5a0af3f6, name=Gayathri, age=31, technology=MySQL}, {id=5ee733f2d5929a1c5a0af3f7, name=Megala, age=34, technology=Java}]

Notice that the asynchronous call returned one employee at a time but the synchronous call gave back all the employees in a list(output enclosed in []).

Here is both the scenarios show together:

	private void getEmployees() {


		WebClient webClient = WebClient.create("http://localhost:8080");

		Flux<Map> employeeMap = webClient.
				get().uri("/getAllEmployees").
				retrieve().bodyToFlux(Map.class);


		// non blocking call
		employeeMap.subscribe(response -> System.out.println(response));


		// blocking call
		List<Map> output = employeeMap.collectList().block();


		System.out.println(output);
	}

Now let’s make a POST call:

Here is how to post an employee to the POST rest service asynchronously:

        WebClient webClient = WebClient.create("http://localhost:8080");
	Map<String,Object> employee1 = new HashMap<String,Object>();
		employee1.put("name","Megala");
		employee1.put("age",34);
		employee1.put("technology","Java");
		Mono<Void> voidMono = webClient
				.post()
				.uri("/saveEmployee")
				.body(BodyInserters.fromValue(employee1))
				.retrieve()
				.bodyToMono(Void.class);

		voidMono.subscribe();

This is similar to get method invocation except that you pass a body (using BodyInserters.fromValue()) and the response returned is a Void object (wrapped in Mono ).

To execute the request , subscribe to the Void Mono object.

In all the examples shown so far we used retrieve() method to fire GET and POST requests. Using this method you can only get the body of the response. If you want to retrieve the headers and status codes use exchange() method instead of retrieve().

Below is an example of firing the same POST request shown above using exchange() method and retrieving the status code:

		Mono<Object> responseCode = webClient
				.post()
				.uri("/saveEmployee")
				.body(BodyInserters.fromValue(employee))
				.exchange()
				.flatMap(clientResponse -> Mono.just(clientResponse.statusCode()));

		responseCode.subscribe(r -> System.out.println("Status Code"+r));

As you see the response returned by exchange() method is then piped through a flat map to retrieve the status code which is wrapped in a Mono object and returned.

The Mono object can then be subscribed for the status response.

To make the above call synchronously , use block method on the Mono Object as below instead of subscribing to it:

		HttpStatus opCode  = (HttpStatus) responseCode.block();


Here is all the scenarios shown together:

private void postAnEmployee() {

WebClient webClient = WebClient.create("http://localhost:8080");

Map<String, Object> employee = new HashMap<String, Object>();
employee.put("name", "Gumutha");
employee.put("age", 21);
employee.put("technology", "Angular");

Mono<Object> responseCode = webClient
.post()
.uri("/saveEmployee")
.body(BodyInserters.fromValue(employee))
.exchange()
.flatMap(clientResponse -> Mono.just(clientResponse.statusCode()));

//non blocking code
 responseCode.subscribe(r -> System.out.println("Status Code" + r));

//blocking code
 HttpStatus opCode = (HttpStatus) responseCode.block();

System.out.println("Response" + opCode);

//using retrieve method instead of exchange()

 Map<String, Object> employee1 = new HashMap<String, Object>();
employee1.put("name", "Megala");
employee1.put("age", 34);
employee1.put("technology", "Java");
Mono<Void> voidMono = webClient
.post()
.uri("/saveEmployee")
.body(BodyInserters.fromValue(employee1))
.retrieve()
.bodyToMono(Void.class);

voidMono.subscribe();


}

That’s it!

We have used WebClient.create() method to create the web client.

You can also use WebClient builder to build the web client with more configurations such as setting headers , cookies, filters etc .


Posted

in

,

by

Comments

Leave a Reply

Discover more from The Full Stack Developer

Subscribe now to keep reading and get access to the full archive.

Continue reading