I am working on Rest API using Spring boot and I had to access an application's endpoint. I used RestTemplate for it. I was able to do it using 2 methods,
postForEntity():
responseEntity =
restTemplate.postForEntity(uri, httpEntity, ResponseClass.class);
exchange():
responseEntity =
restTemplate.exchange(uri, HttpMethod.POST, httpEntity, ResponseClass.class);
I would like to know the usage and differences of these two methods.
I also see another method execute(). Please shed some light on it. How and when to use it.
The RestTemplate is a very versatile object.
Let's start with execute, since it's the most generic method:
execute(String url, HttpMethod method, #Nullable RequestCallback requestCallback,
#Nullable ResponseExtractor<T> responseExtractor, Object... uriVariables)
Note the uriVariables can be passed as a Map too.
execute is designed to be applicable in the highest variety of scenarios possible:
The first and second parameters allow any valid combination of URL and method.
The request can be modified in a myriad of different ways by passing a custom RequestCallback (a #FunctionalInterface with just one method doWithRequest(ClientHttpRequest request)) before sending it.
The response returned from the remote resource can be deserialized in any way necessary by passing a custom ResponseExtractor.
Compare this with exchange:
exchange(String url, HttpMethod method, #Nullable HttpEntity<?> requestEntity,
Class<T> responseType, Object... uriVariables)
There are two major differences here:
You can now pass an HttpEntity directly, whereas before it needed to be set manually using the RequestCallback.
Deserialization mechanics are provided out of the box by passing the desired response type Class.
As you can see, this is much more convenient for everyday use.
Methods like getForEntity and postForEntity are even shorter, easier to understand versions of this:
getForEntity(String url, Class<T> responseType, Object... uriVariables)
postForEntity(String url, #Nullable Object request, Class<T> responseType,
Object... uriVariables)
Notice postForEntity now allows you to POST any Object directly without a wrapper. There is no performance benefit or detriment to using these instead of execute, as they call execute themselves under the hood - it's simply a matter of convenience.
RestTemplate is a synchronous client to perform HTTP requests. It offers templates for common scenarios for each HTTP method, in addition to the generalized exchange(...) and execute(...) methods that support less frequent cases.
The Spring Integration documentation summarizes the usage of each method:
postForEntity
Create a new resource via POST and return the representation from the response.
exchange
More generalized, and less opinionated version, of the above methods that provides extra flexibility when needed. It accepts RequestEntity, including HTTP method, URL, headers, and body as input, and returns a ResponseEntity.
These methods allow the use of ParameterizedTypeReference instead of Class to specify a response type with generics.
execute
The most generalized way to perform a request, with full control over request preparation and response extraction via callback interfaces.
In the end, both postForEntity(...), exchange(...) and execute(...) methods will invoke the protected doExecute(...) method, which will perform the actual HTTP request. You can check the source code for details
Execute(..)
The most raw form of method, to make REST call.
Exchange(..)
A wrapper over Execute method.
PostForEntity(..)
A wrapper method, which further eases the use for making REST calls.
You specify the request type in the method name itself(getForEntity, postForEntity), so,
need not mention request type in the parameter.
The method name in itself becomes self explanatory.
In Exchange & postForEntity, response has to be in Json formats.
This Json is further converted to Model class by json-mapper libraries.
While, in Execute, we accept response in any format, as we pass the deserializer in Response Executor argument.
If you look at the implementation of both postForEntity and exchange method you will see that both use the execute methods in the back. Using the exchange method will give you more freedom for calling different http methods.
Related
I know sending a body with a GET request isn't the best idea but I'm trying to consume an existing API which requires it.
Sending a body with POST is straight-forward:
webClient.post()
.uri("/employees")
.body(Mono.just(empl), Employee.class)
.retrieve()
.bodyToMono(Employee.class);
It won't work with webClient.get() though, because while the post() method returns a WebClient.RequestBodyUriSpec, the get() method returns WebClient.RequestHeadersUriSpec<?>, which doesn't seem to allow any body definitions.
I've found a workaround for Spring RestTemplate here: RestTemplate get with body,
but had no luck finding any for the new WebClient.
While the other responses are correct that you shouldn't use a body with a GET request, that is not helpful when you do not own, or cannot change the already existing method you are calling.
The problems is WebClient#get returns a WebClient.RequestHeadersUriSpec which does not provide a way for us to set the body.
WebClient#post returns a WebClient.RequestBodyUriSpec which does provide us a way to set the body but will cause us to use the wrong HTTP method, POST instead of GET.
Thankfully for us stuck in this situation there is WebClient#method which returns a WebClient.RequestBodyUriSpec and allows us to set the HTTP method.
webClient.method(HttpMethod.GET)
.uri("/employees")
.body(Mono.just(empl), Employee.class)
.retrieve()
.bodyToMono(Employee.class);
You may still run into issues in your testing libraries though...
A GET reques has no body. It is forbidden (well, not forbidden, but not used at all) by the HTTP specification. You have two approaches here:
Do a POST. It is there just for that.
Use a query string and pass the data in that part of the URL.
Of course, you can attach the needed fields and pass a payload to the GET request, but it will probably be ignored, or worse, identified as an error and rejected by the server, before your served code has access to it. But if you are passing data to the server to do some processing with it, then POST is what you need to use.
Extracted from RFC-7231. HTTP 1.1. Semantics and code:
A payload within a GET request message has no defined semantics;
sending a payload body on a GET request might cause some existing
implementations to reject the request.
(markup is mine)
Reasons for this are, mainly, that a GET method must be idempotent, producing the same output for the same URL, if repeated. POST doesn't have these requirements, so POST is your friend.
Came across spring boot code snippet which has HttpServletResponse passed has an argument in the controller method
public void someApiMethod(#RequestBody MyRequest req, HttpServletResponse response) {
//some code
response.setStatus(HttpStatus.NO_CONTENT.value());
}
The same could have been achieved using ResponseEntity and I feel there is no need of passing HttpServletResponse here.Kindly advise on which is the best approach and why, considering this code is written for rest API ?
Better solution is to use #ResponseStatus for there is no real reason to add non-API arguments, such as HttpServletResponse or ResponseEntity in controller methods. Only path variables, request params, request body & headers should be the set of controller parameters for majority of cases. Plus it is more readable, maintainable, and still is usable by Swagger etc.
#ResponseStatus(code = HttpStatus.NO_CONTENT)
public void someApiMethod(#RequestBody MyRequest req) {
//some code
}
Spring boot (and in particular Spring MVC which is a part of spring boot in this case) provides an abstraction over low-level HttpResponse which is a part of the servlet specification.
In a nutshell, this abstraction saves you from thinking in terms of Http Protocol and allows concentrating on a business logic which is a good thing.
So if you can avoid HttpServletResponse - do it by all means (and this is what you'll usually do in your applications).
You can create objects (and spring will convert them for you if its REST), you can return ResponseEntity which is "status" + "body" - spring will do all the conversions.
So consider these techniques first.
Now, sometimes you have to manipulate the response at the low level, well in this case you have to work with HttpServletResponse object.
Example of this if you want to return a binary data that cannot be easily converted. For instance, if you want to prepare a zip file and send it back as a result of HTTP request, you'll have to get a more fine-grain low-level control, in this case, it's better to start off with HttpServletResponse param passed into controller method.
It depends on your particular use case.
If you can implement your use case without directly accessing the HttpServletResponse object, do so by any means. It is the cleaner approach.
You might have a scenario in which you need to access the HttpServletResponse. Such an example would be when you need to stream content back to the client, so you need direct access to the response output stream. In recent versions of Spring this can also be achieved via StreamingResponseBody, which avoids the need to directly access the response outout stream.
I believe it is a better approach to return a ResponseEntity and use that as per your suspicious.
ResponseEntity is easier to handle and a more "elegant" solution, more consistent with Spring design.
My service method Produces one of this MediaTypes it may produce pdf or excel file or other.
#Produces({"application/pdf","application/vnd.ms-excel"...
My Question
My service returns response type with application/pdf always even if it produces excel. Why?
Than I rearranged MediaTypes.
#Produces({"application/vnd.ms-excel","application/pdf",...
Now it's giving type application/vnd.ms-excel for all responses,again Why?
I am using com.sun.jersey API for client and getting type by the use of
clientResponse.getType()
Probably I think I misunderstood the concept of #Produces annotation.
Please Clarify.
Following is code of my Service method.
response = Response.ok((Object) file);//file is Object of File
response.header("Content-Disposition","attachment; filename="+filename);
//filename can be a.pdf b.xlsx etc
return response.build();
JAX-RS methods should base the preferred content type on the value of the Accept header of your request. Failing that, it should default to the first specified.
While the JAX-RS spec is somewhat vague on the subject, the Jersey documentation is very clear in describing the selection mechanism.
As it said in the documenation:
#GET
#Produces({"application/xml", "application/json"})
public String doGetAsXmlOrJson() {
...
}
The doGetAsXmlOrJson method will get invoked if either of the media types "application/xml" and "application/json" are acceptable. If both are equally acceptable then the former will be chosen because it occurs first.
Also, you can use quality factor for specifying which media type is more preferable:
#Produces({"application/xml; qs=0.9", "application/json"}).
In any way, if you want to be sure about which media type is used, you should divide your methods into two different signatures.
The #Produces annotation is used by the JAX-RS implementation to bind the incoming request to one of your Resource Methods, based on the accept header of the request.
You can set the exact type of the response in the returned Response object using ResponseBuilder#type(MediaType) if you want to enforce one media type in particular.
If you want to match the accept header of the incoming request ("application/vnd.ms-excel" vs "application/pdf" in your case), you can retrieve that header by adding a parameter annotated with #HeaderParam("accept") in your Java method.
HTH.
I have tried to find the answer to this, but I cannot seem to find what I am looking for. So I apologize if this question already exists.
PROBLEM:
I want to be able to access the request type of a request inside of a generic method within my Controller.
DESCRIPTION:
Using Spring ROO and Spring MVC, I have developed a small web service that will respond with certain tidbits from a database when queried. In one of my controller classes, I have some methods that handle some variety of GET, PUT, POST, etc., for the URIs that are mapped within the #RequestMapping parameter.
For example:
#RequestMapping(method = RequestMethod.Get, value = "/foo/bar")
#ResponseBody
public ResponseEntity<String> getFooBar() {
// stuff
}
If a request is made to the web service that it is not currently mapped, a 405 error is returned (which is correct), but I want to return more information along with a 405 response. Maybe respond with something like:
"I know you tried to execute a [some method], but this path only handles [list of proper methods]."
So I wrote a short method that only has the RequestMapping:
#RequestMapping(value = "/foo/bar")
I have found that the method with this mapping will catch all unhandled request types. But I am having trouble accessing the information of the request, specifically the type, from within the method.
QUESTION:
A. How can I access the request type from within the method? OR
B. Is this the right approach? What would be the right approach?
EDIT
ANSWER:
I added a HttpServletRequestobject to the method parameters. I was able to access the method type from that.
I tried using HttpRequest, but it didn't seem to like that much.
Thanks all!
You can add a method parameter of HttpServletRequest, but I think you'd be better off continuing to reply with 405. A client should then make an HTTP OPTIONS call (see How to handle HTTP OPTIONS with Spring MVC?) and you can return the list of allowed methods there.
A. you can access request if you mentioned it as parameter in controller method
public ... getFooBar(HttpRequest request) {
...
}
B. you do not need to add any other description as the 405 status is descriptive.
In answer to "A", just add "HttpRequest req" as an additional argument to your controller methods. Spring will automatically inject a reference to the request, and you can play with headers to your heart's content.
In answer to "B" - "What would be the right approach", how about this?
In order to return that 405, Spring has raised a MethodArgumentNotValidException. You can provide custom handling for this like so:
#ExceptionHandler(MethodArgumentNotValidException.class)
#ResponseStatus(HttpStatus.BAD_REQUEST)
#ResponseBody
public MyMethodArgumentMessage handleMathodArgumentNotValidException(
MethodArgumentNotValidException ex) {
BindingResult result = ex.getBindingResult();
MyMethodArgumentMessage myMessage =
new MyMethodArgumentMessage(result.getFieldErrors());
return myMessage;
}
You should take a look at the #ExceptionHandler annotation. This lets you add methods such as the following to your controller. You can define your own exceptions and appropriate custom handlers for them. I use it to return well-structured XML and JSON from REST services. Although for it to work, you need to throw specific exceptions from your controller methods.
A good walk-through of using this was provided by Petri Kainulkainen in his blog:
http://www.petrikainulainen.net/programming/spring-framework/spring-from-the-trenches-adding-validation-to-a-rest-api/
Currently I have registered a Gson Provider which correctly is
used whenever my request is consuming or producing json.
The problem is that I have a request that needs the Post data as
either a byte[], InputStream, Reader, or String.
The reason I need the "raw" data is that I have some third party code where
it expects to do its own deserialization.
No matter which of these four types I specify my Post method to expect,
the GsonReader will complain and rightly so.
Expected a string but was BEGIN_OBJECT
Depending on the type there is a different error, but it all boils down to the
fact that I don't want this Provider/MessageBodyReader to run.
Also, I don't have control of the Accept and Content-type headers of the Posted data.
They will be application/json.
You can "modify" the accept/content-type headers of a request in a filter. So, if there is any way you can recognize that for this request, you don't want to use GSON, you can write a ContanerRequestFilter that modifies the headers.
If using GSON provider depends on a method the request gets matched to, you can implement ResourceFilterFactory that applies (returns) the ContainerRequestFilter (that modifies the content-type header to something other than json) just for the applicable methods (you can even introduce a custom annotation, annotate such methods with it and in the resourcefilterfactory return the containerrequestfilter only if the method passed to it is annotated with that annotation).
Here are the relevant links:
ContainerRequestFilter javadoc
ResourceFilterFactory javadoc
RolesAllowedResourceFilterFactory - you can use this as an example of a resource filter factory implementation