Spring integration with cache and http.outboundGateway - spring

I am trying to implement the cache to avoid multiple calls to Rest API. Below is the implementation code for API call. Instead of calling API every time, I need to put the API results in hashmap using payload object as key and result as value. I tried different ways but I was not able to find the solution. Please, can you help me with this.
#Bean
public IntegrationFlow read() {
return IntegrationFlows.from("input").split(new PayLoadSplitter()).enrichHeaders(p -> p.header(HttpHeaders.ACCEPT, MediaType.APPLICATION_XML))
.handle(Http.outboundGateway("http://localhost:8080/service/publications/{name}")
.httpMethod(HttpMethod.GET).expectedResponseType(String.class).uriVariable("name", p->p.getPayload())).aggregate().get();
}

Related

Ways to handle exceptions like WebClientRequestException due to service unavailability for all calls from a WebClient instance than individually

As the title suggests, I'm using Spring WebClient to invoke an external api and process the response. I have added a ExchangeFilterFunction to handle the response based on the status code returned from the server as something like below.
ExchangeFilterFunction responseProcessor() {
return ExchangeFilterFunction.ofResponseProcessor(response -> {
if (response.statusCode().isError()) {
return Mono.error(new RuntimeException("WebClient Error"));
}
return Mono.just(response);
});
}
Now, this works fine with services that return a response for the request when it is up. But when the service is down, the request fails with WebClientRequestException which is fine but the error thrown is not handled by the responseProcessor and gets propagated.
I'm aware that the error can be handled on the WebClient call using any of the onErrorXXX methods. But if we use that WebClient instance to make many calls across different parts of the code, the handling looks inefficient. So, I'd like to know whether there's a way to handle this error for all calls done by that webclient instance instead of handling it in all of individual invocations. Something like what the responseProcessor does for all responses.
when you use .exchangeToMono() or .exchangeToFlux() methods it will give you back a mono or flux .
there is an interesting method on mono or flux which is transform() .
transform take a function an add it to your flux or mono chain.
you can define a chain as a function anywhere and use this chain many time in different chains.
so define your exception handling chain ( by using onError() method ) as a function and after you get your response by exchangeToMono() or exchangeToFlux() , use .transform method and pass your exception handling chain to it.
any way , there is another way too .
you can create a method which is your proxy to call any external resource , which use webClient in itself.
then you can apply AOP pattern to it and handle exception in this way.

Convert document objects to DTO spring reactive

I'm trying to convert a document object that is retrieved by the ReactiveCrudRepository as a Flux<Client> into Flux<ClientDto>
Now that I figure out a way to do this, I'm not sure if this is blocking or not:
public Mono<ServerResponse> findAll(final ServerRequest serverRequest) {
final Flux<ClientDto> map = clientService.findAll().map(client -> modelMapper.map(client, ClientDto.class)) /*.delayElements(Duration.ofSeconds(10))*/;
return ServerResponse.ok()
.contentType(MediaType.TEXT_EVENT_STREAM)
.body(map, ClientDto.class);
}
I've tried adding the commented delayElements method and it seems it's sending them one by one, so non-blocking.
I think this is more of a nested question, but at the core I want to know how do I figure out if I do something blocking.
Thanks in advance!
You are blocking if you explicitly call to block method or if you are using a standard jdbc connector to connect to the database instead of a reactive one like reactiveMongo provided by Spring Data.
In the snnipet you have posted, there isn't any blocking, but to be totally sure you should review the code of your clientService class and its nested calls (to a repository for example)

How to mock multiple responses for same request using spring's MockRestServiceServer?

Im using MockRestServiceServer for mocking http responses. In a specific scenario i call an endpoint two times and want a different response the second time.
But when i write a second expectation it's like it overwrites my first expectation.
How does one write multiple responses for the same request?
I've found it after some research:
When instantiating a MockRestServiceServer it default gets an UnorderedRequestExpectationManager. Changing this via the Builder in a SimpleRequestExpectationManager adds support for adding multiple responses in the order of defining them.
private MockRestServiceServer createMockServerBy(Class<? extends
RestTemplate> requiredType) {
RestTemplate template = context.getBean(requiredType);
return MockRestServiceServer.bindTo(template).build(new
SimpleRequestExpectationManager());
}
Have you tried WireMock? It's amazing and provides many features to mock APIs. Have a look at http://wiremock.org/

How to write webSockets for Rest calls in Spring-boot?

I'm new to web socket programming. I have more than 10 methods annotated with #GetMapping, where the returned data is read from a MySQL database.
Can anyone help me to know how to write WebSockets.
My WebRestController.java looks like the below:
#CrossOrigin(origins = "http://localhost:4200", allowedHeaders="*")
#RestController
#RequestMapping("/api")
public class WebRestController {
#GetMapping("/summary")
public String Summary() { /* ... */}
#GetMapping("/erday")
public String Erday(String erday) { /* ... */}
#GetMapping("/count")
public String Count(#RequestParam Map<String,String> queryParam,
String date, String target) { /* ... */}
#GetMapping("/details")
public String Details(#RequestParam Map<String,String> queryParam,
String date, String target) { /* ... */}
#GetMapping("/devmawah")
public String DevMawah(#RequestParam Map<String,String> queryParam,
String date, String target) { /* ... */}
// ....
}
I tried before many times in internet to find the solution, but couldn't find it. All I found are examples for Chat applications, which have 2 endpoints to send and receive.
WebSockets are used for bi-directional communication, not really for REST style services (where HTTP is superior in my opinion). The core difference being that HTTP is fundamentally a request-reply protocol, which fits very well to REST whereas WebSocket is centred around messages. Of course, you can argue that request-reply is a specialisation of message-based communication.
There are several articles on this topic (google REST over WebSocket) and even some StackOverflow questions which detail the pros and cons, for example Is ReST over websockets possible?.
The only way that I know of which allows you to do something resembling REST over WebSocket without having to re-write the RestController is swagger-socket, but I would not recommend using it as the project seems to be inactive now and it seems to not have been used extensively.
Alternatively, you can replace your #RequestMapping or #GetMapping annotations with #MessageMapping annotations and model your API through messages (e.g. the client sends a "GET" message to a given destination, and you send back a message containing the resources).
I can say 99% of reasons that brings us to the idea of Rest Over Websocket is just because we are looking at the problems from wrong direction.
But I wrote such library because I am going to need it in another dummy project I will write later, and you can check it out.
Basically what it does is to scan your controllers, and create a websocket handler that can pass data to those controllers, depending on path, method, and inputs. But there is a lot more it handles internally to achieve this goal.
I havent started the docs yet, so, you can check the sample from website for now.
Well... Just my little contribution...
First you you should code your websocket handler (taking into account the potential size the payload). Then, you should create a config class to register your hander (I am thinking not in a stomp version).
In your handler, after you stablish the connection with the websocket server, you should have a custom component to hold the sessions (maybe a map of usernames and a session wrapper). This is useful, as you you could send messages not only through the ws connection but also through a rest api endpoint (you could hit an endpoint or using an scheduler tasks to periodically send messages to certain users upon certain conditions). Will post again a link later

Spring controller method invocation advice

I have a controller that exposes the following endpoint:
#RequestMapping("/all-users")
List<User> getAllUsers() {
...
}
I have also an annotation that helps me out with versioning of those endpoints, which ends up on something like this:
#RequestMapping("/all-users")
#Version(version=1, latests=LATEST_ALL_USERS)
List<User> getAllUsers() {
...
}
Now I want to introduce an additional standard behavior to all handlers mapped wish method contains #Version annotation which will simply wrap the response object into another object which contains the current version and latest version of the invoked method. Some information to build this object are provided by #PathVariable parameters. I'm trying to find a hook that allows me that but no luck so far.
I tried first to have a custom RequestResponseBodyMethodProcessor but if I add it will not take any effect because the original RequestResponseBodyMethodProcessor comes before and I don't want to remove the ResponseBody from my endpoints.
Afterward I tried to go for the mapping instead, once I cannot handle it on the processor, maybe I could handle that on mapping time introducing my code pre and post method invocation, but got stuck on the point where mapping is registered where a method object is needed, not allowing me to introduce my advice code.
Is there any way to get this done?
Edit:
Some of the information needed to build the new returned object are provided as #PathVariables, and are available on end-point method call.

Resources