In my application based on REST API, I need to return for all results of all requests, a custom field in the Response Headers. Now I use this approach:
response().setHeader("custom-field",valuateSender());
return ok(response.addData(body));
In this way, however, I am forced to call the result() method in all my actions, I'm looking for a more general and more intelligent approach.
You can add a Filter which will be global and applies to all of your routes.
then delegate the response and add your custom header before returning data to the client.
this could be a part of your filter:
public class AddCustomHeaderFilter extends Filter {
#Override
public CompletionStage<Result> apply(
Function<Http.RequestHeader, CompletionStage<Result>> nextFilter,
Http.RequestHeader requestHeader) {
return nextFilter
.apply(requestHeader)
.thenApply(
result -> {
return result.withHeader("custom-key", "custom-data");
});
}
}
more info on Filters:
https://www.playframework.com/documentation/2.8.x/JavaHttpFilters
Related
I kind of hit the wall with DeferredResult. We have really old pattern where we have Interfaces that contains all rest annotations and implementation of them. Also other clients (microservices) uses those interfaces to map communicate with each others (they are importing them as a module and make proxy rest calls). But there is a problem somebody hacked a bit this approach and we had two different declarations one for clients without DeferredResult and one with it on implementation side. When we tried to reflect changes for clients there is a problem a lot of them needs to change a way of communication. So i've been thinking of removing DeferredResult from method signature and just use result.
My question is how to do it in non blocking way in Spring?
Let's say i have this kind of code
#Component
public class ExampleSO implements ExampleSOController {
private final MyServiceSO myServiceSO;
public ExampleSO(MyServiceSO myServiceSO) {
this.myServiceSO = myServiceSO;
}
#Override
public DeferredResult<SOResponse> justForTest() {
CompletableFuture<SOResponse> responseCompletableFuture = myServiceSO.doSomething();
DeferredResult<SOResponse> result = new DeferredResult<>(1000L);
responseCompletableFuture.whenCompleteAsync(
(res, throwable) -> result.setResult(res)
);
return result;
}
}
where:
#RestController
public interface ExampleSOController {
#PostMapping()
DeferredResult<SOResponse> justForTest();
}
and:
#Component
public class MyServiceSO {
public CompletableFuture<SOResponse> doSomething() {
CompletableFuture<SOResponse> completableFuture = new CompletableFuture<>();
Executors.newCachedThreadPool().submit(() -> {
Thread.sleep(500);
completableFuture.complete(new SOResponse());
return null;
});
return completableFuture;
}
}
How could i achieve something like this:
#RestController
public interface ExampleSOController {
#PostMapping()
SOResponse justForTest();
}
Without removing async benefits ?
I'm using a RouterFunction to define endpoints in my Spring Boot application. My service returns a Mono<Object> and I want to return the result of this when the endpoint is called. I also need to authenticate so I pass a UserPrinciple object through.
Router
#Bean
RouterFunction<ServerResponse> router() {
return route()
.GET("/api/endpoint-name", this::getExample)
.build();
}
private Mono<ServerResponse> getExample(ServerRequest request) {
return ServerResponse.ok().body(fromPublisher(getUserPrincipal().map(service::getSomething), Object.class)).log();
}
private Mono<UserPrincipal> getUserPrincipal() {
return ReactiveSecurityContextHolder.getContext()
.map(ctx -> ctx.getAuthentication())
.map(auth -> auth.getPrincipal())
.map(UserPrincipal.class::cast);
}
Service
public Mono<Object> getSomething(UserPrincipal userPrincipal) {
WebClient webClient = getWebClient(userPrincipal.getJwt());
return webClient.get()
.uri(uriBuilder -> uriBuilder.path("another/server/endpoint").build())
.retrieve()
.bodyToMono(Object.class);
}
The endpoint is returning this:
{
"scanAvailable": true
}
which suggests that I'm passing the Mono into the body of the response instead of passing in the result. However I've used fromPublisher which I thought would resolve this.
I can't find any examples where the service returns a Mono and the route correctly returns the result of the Mono.
How can I correctly pass a Mono/Flux as the body of the response?
im not going to explain the difference between mapand flatMapsince i have already written a quite comprehensive explanation here:
Do you have a test to show differences between the reactor map() and flatMap()?
The problem in the above code is the return of Object. And input parameters of Object into certain functions. The first function is pretty straight forward
Mono<UserPrincipal> = getUserPrincipal();
While the second one gets a bit more hairy:
Mono<Mono<Object> value = getUserPrincipal().map(service::getSomething);
So why are we getting A nested Mono?, well the get something returns a Mono<Object> and the Map return according the the api is Mono<R> where R is what we return from getSomething.
We then stick it into the fromPublisher which will unrap the first Mono ending up trying to serialize the Mono<Object>resulting in the strange response.
{
"scanAvailable": true
}
The answer here is pay more close attention to the type system. The body function takes a Publisher (Mono or Flux) so you don't need the fromPublisher function.
And also changing map to flatMap since the return type from inside a flatMap is a publisher.
ServerResponse.ok()
.body(getUserPrincipal()
.flatMap(service::getSomething), Object.class));
I am using spring integration to define a flow that will do two things - firstly execute http call with given payload and then use the response provided and original payload to make another http call.
How can this be achieved? In the code below I am able to use and modify the first payload and use it in the firstHttpRequest but then how can I use the original payload with the response from the firstHttpRequest?
Any good practices?
#Bean
public IntegrationFlow makeHttpCalls(){
return message -> message
.transform(new GenericTransformer<Message<String>, String>() {
#Override
public String transform(Message<String> message){
return message.getPayload() + " first call";
}
})
.handle(makeFirstHttpRequest())
.transform(new GenericTransformer<Message<String>, String>() {
#Override
public String transform(Message<String> message) {
logger.debug("Response from transform: " + message);
return message.getPayload();
}
})
.handle(makeSecondHttpRequest())
.channel("entrypoint");
}
One approach is .enrichHeaders() and place that original payload into one custom header. Therefore downstream, after response, get deal with that header to restore an original payload.
Another approach is .enrich() when you make an external call and enrich original message with info from reply.
There is other tools, like .routeToRecipients() and .publishSubscribeChannel() where you send the same message to different sub-flows for different logics.
But that's it what you have to choose.
My problem concerns the creation of a custom method within an action. I'm using Struts2 and REST Plugin in order to implement a RESTful WebService. My action class is the following:
public class SampleController implements ModelDriven<Object> {
private Sample sample = new Sample();
private Collection<Sample> list;
private int id;
public HttpHeaders create() {
sdao.save(sample);
return new DefaultHttpHeaders("create");
}
public HttpHeaders destroy() {
return new DefaultHttpHeaders("destroy");
}
public HttpHeaders show() {
return new DefaultHttpHeaders("show").disableCaching();
}
public HttpHeaders update() {
sdao.save(sample);
return new DefaultHttpHeaders("update");
}
public HttpHeaders index() {
list = sdao.findAll();
return new DefaultHttpHeaders("index").disableCaching();
}
public Object getModel() {
return (list != null ? list : sample);
}
public int getId() {
return id;
}
public void setId(Integer id) {
if (id != null) {
this.sample = (Sample) sdao.findById(id);
}
this.id = id;
}
}
I can access to a resource via a GET HTTP method correctly. In order to use a custom method, called by passing a parameter to search resources i.e
public searchBySenderName(String senderName) {
list.addAll(sdao.findBySenderName(senderName))
}
What is the correct procedures? How can I call it via GET following URL?
You can call custom method from any of the predefined methods for GET (index, show) in your case, see RESTful URL mapping logic .
RESTful URL Mapping Logic
This Restful action mapper enforces Ruby-On-Rails REST-style mappings.
If the method is not specified (via '!' or 'method:' prefix), the
method is "guessed" at using REST-style conventions that examine the
URL and the HTTP method. Special care has been given to ensure this
mapper works correctly with the codebehind plugin so that XML
configuration is unnecessary.
Of course you can change the method names used by the action mapper, but it will affect a whole application. If you already occupied a resource URL then you should use another to perform its job. This is in case if you are using a strict rest mapper. In the mixed mode you can map an usual action to some action method.
REST and non-RESTful URL's Together Configuration
If you want to keep using some non-RESTful URL's alongside your REST
stuff, then you'll have to provide for a configuration that utilizes
to mappers.
Plugins contain their own configuration. If you look in the Rest
plugin jar, you'll see the struts-plugin.xml and in that you'll see
some configuration settings made by the plugin. Often, the plugin just
sets things the way it wants them. You may frequently need to override
those settings in your own struts.xml.
And last, you mightn't specify a method via ! or method: prefix because it's restricted by default configuration.
I've searched on this and found a few near misses. I've created a java client to consume a web service using JAX-WS. Is there a way when using JAX to set the HTTP_USER_AGENT value? I would like to have my web service log when specific clients (mine) access it so I wanted a customized value.
I've seen options where you set it in the system properties but this doesn't seem to work. The generated JAX classes don't seem to have a direct reference to the connection object so I don't see how I can manipulate those classes.
Any help would be great.
Thanks
ST
The solution to this kind of problem in JAX-WS is to implement a SoapMessage Handler (Interface: SOAPHandler< SOAPMessageContext >).
Within that handler you insert your HTTP header into maybe already existing headers, then you give control to the next handler in the handler chain.
The concept of this handler chain is kind of nice, you can have small classes for a very specific purpose (Security, Logging etc.).
In your client you configure the handler chain prior to sending any request:
// HandlerChain installieren
Binding binding = ((BindingProvider) port).getBinding();
List hchain = binding.getHandlerChain();
if (hchain == null) {
hchain = new ArrayList();
}
hchain.add(new HTTPUserAgentHandler());
binding.setHandlerChain(hchain);
And here is the code for the HTTPUserAgentHandler:
public class HTTPUserAgentHandler implements SOAPHandler<SOAPMessageContext> {
#Override
public boolean handleMessage(SOAPMessageContext context) {
boolean request = ((Boolean) context.get(SOAPMessageContext.MESSAGE_OUTBOUND_PROPERTY)).booleanValue();
if (request) {
#SuppressWarnings("unchecked")
Map<String, List<String>> headers = (Map<String, List<String>>) context
.get(MessageContext.HTTP_REQUEST_HEADERS);
if (null == headers) {
headers = new HashMap<String, List<String>>();
}
headers.put("HTTP_USER_AGENT", Collections.singletonList("user_agent"));
context.put(MessageContext.HTTP_REQUEST_HEADERS, headers);
}
return true;
}
#Override
public boolean handleFault(SOAPMessageContext context) {
return true;
}
#Override
public void close(MessageContext context) {}
#Override
public Set<QName> getHeaders() {
return null;
}
}
Let me question the idea of having HTTP header first.
A more correct (WS-centric) approach is to set SOAP Header, not HTTP header. Consider this: SOAP messages can be delivered not only by HTTP, but by JMS, SMTP or custom transports. By requiring to have user-agent HTTP Header, you unnecessary tie you code to only one transport, albeit currently prevailing.
This is the reason BTW why JAX-WS have no notion of HTTP headers except in handlers.
And (of course) StackOverlow knows how to create SOAP headers.
not sure if this is the best/most direct way to do it, but i think you could add a custom javax.xml.ws.handler.Handler to the handler chain in the dispatch javax.xml.ws.Binding. in the Handler, you should be able to set a custom map of extra http headers on the outgoing MessageContext using the MessageContext.HTTP_REQUEST_HEADERS property.