Provide the actual HTTP GET request within the response - java

I would like to provide the actual get request in a response. I am free to choose between placing that information into the header or the body of the response.
The current project setup includes:
Nginx as reverse proxy
Spring boot application
which are potential candidates to put in that logic.
Request:
GET http://localhost/api/users/2/photos/2
Response:
BODY {"some": "values",
"_request": "GET http://localhost/api/users/2/photos/2"}
or
HEADERS "custom-header-get-request": "GET http://localhost/api/users/2/photos/2"
BODY {"some": "values"}
I can easily add the information to the response of each Responseobject within the Controllers of the spring boot application. This approach is quite cumbersome, as it leads to a lot of codechanges and allways needs to be in mind that each Controller should take care of providing the requestinformation to the response, achieving the first solution.
Which other options do i have?

Related

Is it possible to programmatically resolve producible content-type given a request in spring-webflux?

My application uses spring-webflux, it still uses classic #Controllers with #RequestMapping-annotated handler methods.
Some methods produce application/json, while others produce text/event-stream.
When a request hits a controller, there is no problem: each mapping has produces with the corresponding media type defined.
The application also uses spring-security (the reactive flavor). If an unauthenticated request arrives, we must build a error response using correct format: JSON for application/json endpoints and a Server-Sent-Event for text/event-stream endpoints.
The problem is that security checks are made before the request handler is resolved, so Spring has no clue about the correct response media type at this point.
If a client sends Accept header, this solves the problem: we just parse it and decide what content type to use, with something like the following:
request.getHeaders().getAccept().contains(MediaType.TEXT_EVENT_STREAM)
(the algorithm is oversimplified, but you get the idea).
But some clients do not send Accept header at all. Strictly speaking, we have all the information we need: we have request, and, somewhere in spring-webflux beans information about all the mappings is stored.
So the question is: how (only having ServerWebExchange instance and access to Spring context) do you make use of this mapping information to find out what media types are supported by a handler corresponding to the current request?
P.S. What I tried/thought of so far:
Manually maintain list of all streaming endpoints... yuck!
Use a bean post-processor to collect information about all mappings and then try to emulate spring-webflux behavior... cumbersome and probably fragile.

Camel Rest-DSL required param ignored

I have a Rest API, created with Camel Rest-DSL. There is a rest, that consumes GET with a list of params, some of which are mandatory.
Route config:
rest().get("/{{camel.rest.version}}/myget")
.param()
.name("accountNumber")
.dataType("string")
.type(RestParamType.query)
.required(true)
.endParam()
.param()
.name("someId")
.dataType("string")
.type(RestParamType.query)
.required(false)
.endParam()
.produces(REST_PR_CN_TYPE)
.responseMessage().code("200").message("OK").endResponseMessage()
.responseMessage().code("500").endResponseMessage()
.route().routeId("rst_cardsInfo")
.log(LoggingLevel.INFO, "ApiRq Recieved http request")
.log(LoggingLevel.DEBUG, "AccountNumber: ${header.accountNumber}, SomeId: ${header.someId}")
.id("rst_rst_info_recieved")
.to("direct:drt_rst_info")
.endRest();
When I open swagger-ui generated page, my API is looks fine. Param accountNumber is marked as required, someId - as not required.
Using any other tool I can send a request without any params and receive HTTP.200 as a response. I expected, that if a param is required, but not present in request, the request would fail. Spring Rest for example makes sure that all mandatory params are present.
Is there any mandatory params presence validation in Camel? May be I misconfigured something?
Ah okay. There is no / only a little bit of validation today in the rest-dsl. It relies on the chosen HTTP component (servlet, restlet, undertow etc.) to do that.
But frankly we can improve thise and let camel-core do some pre-validation if the options has been specified as in your example.
I have logged a ticket: https://issues.apache.org/jira/browse/CAMEL-12533
Thank you, #Claus Ibsen.
From Camel 2.22 version onwards, now we can validate incoming client request.
The validation is turned off by default. In order to configure it, we need to use clientRequestValidation as follow :
restConfiguration()
.component("restlet").host("localhost").port("port")
.clientRequestValidation(true);
For more details visit : Client Request Validation - Apache Camel Manual

Spring MVC: get content negotiation result in a #ExceptionHandler

I want to write an #ExceptionHandler so JSON requests will get an error response in JSON as well. For non-JSON requests, I want the servlet container to send its default HTML response.
To do this, I'll need to do some content negotiation. Spring MVC handles it for normal requests via annotations, but no such annotation is available for #ExceptionHandlers.
I am wondering how can I programmatically call the content negotiation code?
So apparently, content negotiation happens after the error handler is called, so I have to do most of the heavy lifting myself.
The method to use is ContentNegotiationManager.resolveMediaTypes(), which gives a list of types that one will have to go through and make a decision.
An example of how to do this can be found the source of ContentNegotiatingViewResolver.getMediaTypes()

How exactly works the #ResponseStatus Spring annotation for RESTful application?

I am studying for the Spring Core certification and I have some doubts about how Spring handles REST requests.
I know that with REST the resources are exposed as name and that the actions on these resources are the HTTP methods, such as GET, PUT, POST, and DELETE.
And I know that requests are handled by the use of #RequestMapping annotations over the method that handles the operation on the resource.
From what I have understood, both standard web applications and RESTful applications use some codes to communicate with their clients (the RESTful application have an expanded set of codes) that I think represent the status of the request (for example 200 is the request is a successful GET returning content, etc.).
Now the documentation shows the use of the #ResponseStatus annotation as in this example:
#RequestMapping(value="/orders", method=RequestMethod.POST)
#ResponseStatus(HttpStatus.CREATED) // 201
public void createOrder(HttpServletRequest request, HttpServletResponse response) {
Order order = createOrder(request);
// determine full URI for newly created Order based on request
response.addHeader("Location",
getLocationForChildResource(request, order.getId()));
}
So looking at the previous method I know that it handles HttpRequest POST requests towards the resource named /orders (using REST the resource is seen as an URL, is that correct?).
But what exactly does the annotation below do:
#ResponseStatus(HttpStatus.CREATED) // 201
I know that the 201 status code means that a new resource was created on POST.
And looking at the official documentation I can read:
Marks a method or exception class with the status code and reason that
should be returned. The status code is applied to the HTTP response
when the handler method is invoked, or whenever said exception is
thrown.
So what exactly it means? I think that as is done in the previous example it sets the 201 status that says that the resource is correctly created by the POST request. If this is correct I have 2 questions:
The resource is the /orders URI. So what is created? a file named orders (I think that this assertion is false) or what?
Where the 201 status is put?
201 is an HTTP status code. It indicates that the
request has been fulfilled and resulted in a new resource being created.
So if your server is returning such a status code, then the client understands that some (conceptual) resource was created. What that resource is is your responsibility, you're the server.
A status code is part of the HTTP response status line.
Actually, the JavaDocs for the ResponseStatus annotation warn us not to use this annotation for REST APIs. This annotation will cause Spring to call the HttpServletResponse.sendError() method, which will result in an HTML Error page. You don't want that in a RESTful service. Here's what it says:
Warning: when using this annotation on an exception class, or when setting the reason attribute of this annotation, the HttpServletResponse.sendError method will be used.
With HttpServletResponse.sendError, the response is considered complete and should not be written to any further. Furthermore, the Servlet container will typically write an HTML error page therefore making the use of a reason unsuitable for REST APIs. For such cases it is preferable to use a ResponseEntity as a return type and avoid the use of #ResponseStatus altogether.

JAX-RS (jersey) -> Angular.js via REST

I have a jersey server up and running. When running from browser directly I get the correct response. However when I try to access the rest service from angular.js's $resource I get the following error in the console when trying to access to the correct url. I've tried to read all materials online, like http://simplapi.wordpress.com/2013/04/10/jersey-jax-rs-implements-a-cross-domain-filter/ to setup a CORS filter, but the guide seems to be dated and cryptic. (im using the newest implementation of jersey).
Failed to load resource: Origin localhost:63342 is not allowed
by Access-Control-Allow-Origin.
method that makes the data I need available in jersey.
#Path("/id/{id}")
#GET
#Produces(MediaType.APPLICATION_JSON)
public boolean validateSSN(#PathParam("id") String id) {
IdValidator idv = new IdValidator(id);
return idv.Validate();
}
accessor method in angular.js:
services.factory('ReplyFactory', function ($resource) {
console.log("test");
return $resource(baseUrl + '/myproject/api/validate/id/:id', {id: '#id'},
{'get': { method: 'GET' }});
});
Well what you need to do is to ensure that all responses from your resources have following http headers:
Access-Control-Allow-Origin - specifies from which origins requests should be accepted (localhost:63342 in your case)
Access-Control-Allow-Headers - specifies which headers are allowed to be used via CORS
Access-Control-Allow-Methods - specifies which methods are allowed to be used via CORS
And there are other headers like Access-Control-Allow-Credentials and etc.
So you just need to add at least Access-Control-Allow-Origin header to your responses. How you can do it depends on your environment.
You can manually define those headers on each resource .
You can define Jersey filter to add CORS headers to all responses
You can use servlet filter to add CORS headers to all responses
There are also specific solutions for Tomcat and Jetty
There many ways how to do it but all of it is about the same thing - you just add an extra header to your server responses.

Categories