I have the following line of code in my project.
#RequestMapping(value = UrlHandler.GET_AUTHENTICATION,
produces = {"application/json"},
consumes = {"application/json"},
method = RequestMethod.POST
)
What is this produces and consumes meaning in the above lines.
The code is made for RESTful APIs, which means Representational State Transfer, in another words your representational data can change as per the request made to them.
For example if the client request for data in the XML format it will negotiate the content like
consumes = {"application/xml"}
Or if it wants data in JSON it will negotiate content like this:
consumes = {"application/json"}
On the server side you can have both the statement as
produces = {"application/json"}
or
produces = {"application/xml"}
This means that your service can generate data in XML or JSON as per what client has requested. This is part of content negotiation. In HTTP network calls, you can change the Header value to get different representation of same data thanks to REST.
The code mentioned by you states that, it will take JSON data and will produce JSON data.
It specifies the supported media type of the request (consumes), and the media type of the response (produces).
https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/RequestMapping.html#consumes--
Simple - Every request has an Input & Output. (Void sometimes means empty)
The data types ('http media type') related to the inputs are Consumes & output are Produces.
In simple terms, you can say what server expects and what you send.
Say server API expects application/JSON response and you send application/x-www-form-urlencoded then it gives an error.
Related
When I usually make controller endpoints with Java Spring that return JSON data, my return type is usually String; I'll toString() my JSON objects and parse them in my Javascript. Recently, I read somewhere that that wasn't the "correct" way to do it (trying to follow best practices and guidelines). I am starting a new project where my return type is a JSON object (dependency is org.json).
When I try to hit the endpoint in the browser, I'm getting a 406 error with a description of "The resource identified by this request is only capable of generating responses with characteristics not acceptable according to the request "accept" headers.".
Here is what my endpoint looks like now:
#RequestMapping(value = "/api/get-items", method = {RequestMethod.GET, RequestMethod.POST}, headers = "Accept=application/json")
#ResponseBody
public JSONObject doGetItems(HttpServletRequest request, HttpServletResponse response) {
JSONObject data = new JSONObject();
JSONArray items = new JSONArray();
JSONObject item1 = new JSONObject().put("id", 123);
JSONObject item2 = new JSONObject().put("id", 456);
JSONObject item3 = new JSONObject().put("id", 789);
items.put(item1).put(item2).put(item3);
data.put("data", items);
return data;
}
How can I get this to work and return JSON? Or am I supposed to be returning a stringified version of my JSON object and I was doing this correctly all along?
Update
First, I tried taking out the headers parameter in the #RequestMapping annotation. I still got a 406 error.
I then tried changing/adding the parameters in the #RequestMapping annotation, with no luck as well. This is what I tried changing it to:
#RequestMapping(value = "/api/get-items",
method = {RequestMethod.GET, RequestMethod.POST},
headers = "Accept=*/*",
produces = MediaType.APPLICATION_JSON_VALUE)
I'm still getting a 406 error.
The HyperText Transfer Protocol (HTTP) 406 Not Acceptable client error response code indicates that the server cannot produce a response matching the list of acceptable values defined in the request's proactive content negotiation headers, and that the server is unwilling to supply a default representation.
Proactive content negotiation headers include:
A client (e.g. your Web browser or our CheckUpDown robot) can indicate to the Web server (running the Web site) the characteristics of the data it will accept back from the Web server. This is done using 'accept headers' of the following types:
Accept: The MIME types accepted by the client. For example, a browser may only accept back types of data (HTML files, GIF files etc.) it knows how to process.
Accept-Charset: The character sets accepted by the client.
Accept-Encoding: The data encoding accepted by the client e.g. the file formats it understands.
Accept-Language: The natural languages (English, German etc.) accepted by the client.
Accept-Ranges: Whether the client accepts ranges of bytes from the resource i.e. a portion of the resource.
By changing or removing header content at client side it should work.
When you specify headers = "Accept=application/json", then you're saying that an Accept header must be present and have exactly that value.
The client didn't send exactly that value, and there is not reason it should be required to do so, because the Accept header value is a comma-separated list of acceptable values, so it just needs to list application/json, it doesn't have to only specify that value.
To fix, replace headers = "Accept=application/json" with produces = "application/json".
Of course, the client still needs to specify that application/json, application/*, or */* is acceptable.
I'm learning how to build RESTful web services using Spring 4, and one thing I'm not clear on is in #RequestMapping. I've seen examples where one uses headers = "Accept=application/xml" and other examples using consumes (or produces) = "application/xml".
For instance, in my own #RestController class, I have this function...
// POST
#RequestMapping(method = RequestMethod.POST, headers = "Accept=application/xml")
public User create(#RequestBody User user) {
LOG.info("User = " + user.toString());
return userService.create(user);
}
What is the difference between using headers = "Accept=application/xml" vs. using consumes = "application/xml"? Or even using headers = "content-type=application/xml"?
Could someone explain the differences between headers and consumes/produces, and when each is used?
SHORT ANSWER
In the example you have above, using headers = "Accept=application/xml" or produces = "application/xml" will both respond to the client the same way i.e. send a response to the client with XML representation.
LONGER ANSWER
i. Headers
For RESTful web services, the client (e.g. your browser) sends a request (e.g. GET, POST, etc.) to a server, and the server will send a response back. This is an HTTP Transaction. Both the request and response have HTTP header fields ("headers"), which define the operating parameters of an HTTP transaction (I will refer to the headers for client request as "request headers", and these differ from headers from server response "response headers").
As part of the request your browser sends to server, there are different request headers and some examples include Accept, Connection, Content-Length etc. and each of these headers have their own function (see a full list of headers here: https://en.wikipedia.org/wiki/List_of_HTTP_header_fields).
Using your code example, if a client does a POST request, Spring will check the request header(s) and if it finds a header Accept with a value of application/xml, it will map the request to the create method you have above (and in your case the server will return an XML response representation to the client).
Let me modify the headers element in the code you provided:
#RequestMapping(method = RequestMethod.POST, headers = "Connection=keep-alive")
public User create(#RequestBody User user) {
...
}
Notice the headers element now has a value of Connection=keep-alive. If a client does a POST request, Spring will check the request header(s) and if it finds a header Connection with a value of keep-alive, it will map that client request to the create method above.
ii. Produces and Consumes
If you used produces="application/xml" for the create method, this means a client request is only mapped to the create method if the client's Accept header matches application/xml. This essentially is the client saying, "Hey server, I prefer to accept your response in XML representation, so send your response to me in XML". Effectively, the produces="application/xml" is also the server saying, "Hey client, I can only produce responses for you in XML representation, so I will send you that format".
Link to Spring documentation reference.
If you used consumes="application/xml" for the create method, this means a client request is only mapped to the create method if the client's Content-Type header matches application/xml (the Content-Type request header describes the representation the client request is coming in). This essentially is the server saying, "Hey client, I can only consume requests in XML representation, so send that format to me".
SUMMARY
The headers element within the #RequestMapping annotation can take different request headers (Accept, Connection, Cache-Control etc.), but the produces element is only concerned with the Accept request header and the consumes element is only concerned with the Content-Type request header.
As the javadoc of HeadersRequestCondition (which handles the value provided in the headers attribute of a #RequestMapping annotation) states
Expressions passed to the constructor with header names 'Accept' or
'Content-Type' are ignored. See ConsumesRequestCondition and
ProducesRequestCondition for those.
So don't use those headers in headers. Use the produces and consumes attributes for Accept and Content-Type.
As to how to use them, the documentation gives examples: for consumes and for produces.
What does Part stand for? And which http request will reduce Parts that can be fetched by HttpServletRequest#getParts() method?
Please give a example, thanks.
It represents the chunks of a HTTP request that was sent with Content-Type multipart/form-data. It can therefore be anything, as each part has its own Content-Type and name, so traditional request parameters, JSON, XML, and that's how files are uploaded.
I have to create a rest web service where in user access data using url. Url has a query parameter named format which can be either text or file. If user chooses text as format then I have to return text data to browser or if user chooses file as format then return a file for user to download. How can I achieve this?
What I have tried so far (not working) :
#GET
#Produces({MediaType.TEXT_PLAIN, MediaType.APPLICATION_OCTET_STREAM})
#Path("/some_path")
public Response some_path (#Context HttpServletRequest request) {
String format = null;
if(request.getParameterValues("format") != null && request.getParameterValues("format")[0] != null) {
format = request.getParameterValues("format")[0].toString();
}
else {
format = "text";
}
File file = new File("/some/file/path.txt");
if(format.equals("text")) {
return Response.status(200).entity("sending some text").build();
} else {
return Response.ok(file, MediaType.APPLICATION_OCTET_STREAM).header("content-disposition","attachment; filename = result.txt").build();
}
}
With above code format=text works properly but format=file throws HTTP Status 406 null error.
Thanks In Advance
The HTTP status you get is
406 Not Acceptable
To quote Wikipedia:
The requested resource is only capable of generating content not acceptable according to the Accept headers sent in the request.
So you client doesn't send a HTTP header of
Accept: text/plain
or
Accept: application/octet-stream
or any combination. Check your client and the header it sends.
You are mixing to approaches. The first, quite popular but not standardized, by providing the hint of the expected result in request's path by using the format parameter (BTW you may use the #QueryParam("format") String format rather than extracting it from ServletRequest). The second approach is the HTTP content negotiation mechanism, in this case using Accept/Content-Type headers. This mechanism is handled by the JAX-RS implementation based on #Produces annotation and providers' classes.
So now, your user is not only required to set the format but also Accept header. It seems that you are using the client which sets the Accept and one of its value is text/plain. That is why it the first case is working, but there is no application/octet-stream or */* (all), so you the JAX-RS expects that the client is not able to process such a content and instead sends him an error 406 Not Acceptable.
The solution here is to remove the #Produces annotation (you are the one who is taking care of the format of the response), or drop the format parameter and let the JAX-RS do his work (probably you will need to register your own provider). If you however stay with your solution then make sure that the correct or no Accept header is send in request (no header means: "I would accept whatever you send").
I recently moved over to Java and am attempting to write some REST tests against the netflix REST service.
I'm having an issue in that my response using rest assured either wants to send a gzip encoded response or "InputStream", neither of which provide the actual XML text in the content of the response. I discovered the "Accept-Encoding" header yet making that blank doesn't seem to be the solution. With .Net I never had to mess with this and I can't seem to find the proper means of returning a human readable response.
My code:
RestAssured.baseURI = "http://api-public.netflix.com";
RestAssured.port = 80;
Response myResponse = given().header("Accept-Encoding", "").given().auth().oauth(consumerKey, consumerSecret, accessToken, secretToken).param("term", "star wars").get("/catalog/titles/autocomplete");
My response object has a "content" value with nothing but references to buffers, wrapped streams etc. Trying to get a ToString() of the response doesn't work. None of the examples I've seen seem to work in my case.
Any suggestions on what I'm doing wrong here?
This has worked for me:
given().config(RestAssured.config().decoderConfig(DecoderConfig.decoderConfig().noContentDecoders())).get(url)
I guess in Java land everything is returned as an input stream. Using a stream reader grabbed me the data I needed.
Until its version 1.9.0, Rest-assured has been providing by default in the requests the header "Accept-Encoding:gzip,deflate" with no way of changing it.
See
https://code.google.com/p/rest-assured/issues/detail?id=154
It works for me:
String responseJson = get("/languages/").asString();