How to consume a Reactive Spring Rest API with WebClient - spring

I need to consume a reactive rest API (built with spring webflux) on a backend job (executable jar).
I've read about Spring WebClient, but I am not understanding some points.
For instance:
WebClient webClient = WebClient.create("http://localhost:8080");
Mono<Person> person = webClient.get()
.uri("/persons/{id}", 42)
.accept(MediaType.APPLICATION_JSON)
.exchange()
.then(response -> response.bodyToMono(Person.class));
On the last line, there is a "bodyToMono". So that's my question:
If the Rest API being called is already a reactive service, do I need to transform the response to a mono? Is there some point I'm missing?
From my perspective, I think could have a way to let explicit in the code that my Rest API is reactive, but probably is something I am not aware about.

Yes it is required.
The whole idea of being reactive is to make sure none of the Thread are blocked for IO.
You may have made your server side service reactive, but when your consuming that what is the benefit you get when your client is blocked untill there is a response from server. Your client thread keeps waiting untill the server responds. Which is not desired.
webClient.get()
.uri("/persons/{id}", 42)
.accept(MediaType.APPLICATION_JSON)
.exchange().block()
will block your current client thread to wait till the server responds. This can block your client thread.
webClient.get()
.uri("/persons/{id}", 42)
.accept(MediaType.APPLICATION_JSON)
.exchange()
.then(response -> response.bodyToMono(Person.class));
Gives you a Mono which is a reference to a publisher that can emit a single value in future. So the client thread is non blocked.
I have blogged explaining this more.
https://dzone.com/articles/spring-5-reactive-web-services

Related

Calling Multiple apis synchronously, spring boot webflux

In my project we are using spring boot webflux, and I have this scenario where i have to call multiple api's from within a particular microservice synchronously.
e.g.
for(String api:apiNames){
//call api's
}
As per my understanding, webClient works asynchronously, until and unless someone subscribe to it it wont release the response.
in my current scenario i have to make use of webclient and I have to call each api only after successfull execution of previous api.
Note:- api response can be anything success/failure
Please help me in implementing this synchronous call
You can use the #block() method to make it synchronous.
Example on a mono (https://projectreactor.io/docs/core/release/api/reactor/core/publisher/Mono.html#block--)
For example on the (asynchronous) webflux webclient:
return webClient.get()
.uri(uri)
.accept(MediaType.APPLICATION_JSON)
.retrieve()
.bodyToMono(String.class)
.block();
The above example will wait with executing any next line of code untill it has received a response.
After which you can just make another call to another api in the same way.
Edit: As pointed out in the comments I would like to add a warning that using #block() is not efficient and you should try and chain more reactive calls and try to avoid making your application non reactive.
A nice post with more details can be found here: https://stackoverflow.com/a/57365926/1326867
Although, the question uses the word "synchronously", the description rather seems to suggest that sequentiality is what is needed, meaning executing each request one after the other.
If that's the requirement, it can be implemented the following way with Reactor:
Flux.fromIterable(apiNames)
.concatMap(apiName -> webClient...) // concatMap ensures sequential execution
However, if the application is a blocking Spring application, then Nick Hol's answer is also a correct one.

How to produce and consume a RabbitMQ message with inside Spring RestController and send it back to the user

Hello Anyone and Everyone. I am working on a Spring Boot application. Here is my problem. I have a Spring RestController with a post-mapping that takes in some data. I am then needing to send that data over RabbitMQ to another application which in return will perform some calculations on that data and then send it back to me which I then want to return back to the user.
I know that RabbitMQ is for async communication. But I need my controller to return the result that comes back from RabbitMQ all in one go. Right now I am using.
#EnableBinding(Sink::class)
class OptimizedScheduleMessageListener {
#StreamListener(Sink.INPUT)
fun handler(incomingMessage: MyDTO) {
println(incomingMessage)
}
}
to retrieve the results from RabbitMQ. Now I just need my Controller to return it.
#PostMapping( produces = ["application/json"])
fun retrieveOptimizedSchedule: Result<MyDTO> {
myUncalculatedDTO: MyDTO()
source.output().send(MessageBuilder.withPayload(myUncalculadeDTO).build())
return ???
}
Any help with this endeavor is much appreciated.
Thanks in Advance.
Spring Cloud Stream is not designed for request/reply processing.
See the Spring AMQP (Spring for RabbitMQ) project.
The RabbitTemplate has sendAndReceive and convertSendAndReceive methods to implement the RPC model.
On the server side, a #RabbitListener method can be used for request/reply.
What you are trying to do is not advised for couple of reasons.
1. The failure of the 'Another application' which consumes the Rabbit
MQ messages will result in Requests being blocked on the controller end.
2. There is a limit on how many requests you can have simultaneously from the server to clients.
What you can do is use any other communication protocol than REST for this specific part. May be Websocket will be an ideal solution. If not you need to have two REST endpoints. One to submit and get back an request-id, another to poll periodically with the request-id and get processed, completed response.

What is the proper way to make an api call via springs `WebClient`, but ignore the result?

What is the proper way to make an api call via springs WebClient, but ignore the result? The ClientResponse object specifically calls out that I have to do something with the result...
Docs:
NOTE: When given access to a ClientResponse, through the WebClient exchange() method, you must always use one of the body or toEntity methods to ensure resources are released and avoid potential issues with HTTP connection pooling. You can use bodyToMono(Void.class) if no response content is expected. However keep in mind that if the response does have content, the connection will be closed and will not be placed back in the pool.
Can I make a WebClient call and ignore the results? or is there a generic catch all "body or toEntity method" that I can use and then ignore?
Prior to Spring Framework 5.2, using the WebClient#exchange() method and dealing directly with the Mono<ClientResponse> could be quite complex or lead to potential memory leaks.
As of Spring Framework 5.2, this has been made much easier for developers and the exchange() method has been deprecated.
Mono<ResponseEntity<Void>> response = webClient.put()
.uri("https://example.org/book/123")
.retrieve()
.toBodilessEntity();
Spring will read the response body (if present) and release the data buffers, and then return the connection to the pool. It's making sure that there's no memory leak, including when additional Reactor operators are used.

WebClient vs RestTemplate

As per spring 5:
WebClient is an interface representing the main entry point for performing web requests.
It has been created as a part of the Spring Web Reactive module and will be replacing the classic RestTemplate in these scenarios. The new client is a reactive, non-blocking solution that works over the HTTP/1.1 protocol
Does that mean, we need to recode for the old applications using RestTemplate if we want to upgrade to Spring 5?
Or there is some workaround to work with RestTemplate in Spring 5?
No, RestTemplate will continue to exist (at least for now). You don't have to replace it with WebClient.
One of the main differences is RestTemplate is synchronous and blocking i.e. when you do a rest call you need to wait till the response comes back to proceed further.
But WebClient is complete opposite of this. The caller need not wait till response comes back. Instead he will be notified when there is a response.
If you need such a functionality, then yes you need to replace your Resttemplate with WebClient.
You can in fact achieve Rest template like synchronous processing in webclient using .block(). But the other way is not possible.
EDIT:
RestTemplate will be deprecated in a future version(> 5.0) and will not have major new features added going forward
According to the Java Doc the RestTemplate will be in maintenance mode. Spring team advise to use the WebClient if possible:
NOTE: As of 5.0, the non-blocking, reactive
org.springframework.web.reactive.client.WebClient offers a modern
alternative to the RestTemplate with efficient support for both sync
and async, as well as streaming scenarios. The RestTemplate will be
deprecated in a future version and will not have major new features
added going forward.
RestTemplate is not really deprecated. But it will not be evolved in the future. So sticking to RestTemplate is perfectly valid if it does what you need.
Another way to put that is that if you need specific usage patterns like streaming, scatter/gatter, or custom timeouts, this won't be covered by RestTemplate and you need to use WebClient instead.
Now using WebClient in a blocking application is fine too. Using block() shouldn't hurt there and Spring MVC controller does partially support reactive return types.
WebClient is Non-Blocking Client, RestTemplate is Blocking Client.
For a long time, spring serves as a web customer. Under the hood, RestTemplate uses the Java API API, which is based on the subject model.This means that the matter will be blocked until the client receives a response. The problem with the blockage code is due to the existence of any string of memory and cpu cycles. Let us consider a lot of applications that are waiting for low services that are needed to produce the result.Sooner or later, requests for the results are collected. As a result, the program creates many issues, which result in depletion of a pool of thread or occupying all of the available memory. We can also experience performance performance due to the cpu switching.
Spring WebClient vs. RestTemplate
WebClient supports asynchronous as well as synchronous calls.
RestTemplate supports only synchronous calls.
No changes are required in old code even if the RestTemplate is depracated(as long as you don't need asynchronous behaviour)

Spring ResponseEntity - how to return HTTP 100 Continue

Having rest services using Spring-boot 1.5.8.RELEASE some of the services may take time to process.
My idea is to use HTTP 100 Continue so the response will not time out and then return the final response.
I haven't find any way how to do that
Thanks for any hint

Resources