I have this api:
#Path("test")
#GET
#Consumes({MediaType.APPLICATION_JSON})
#Produces({MediaType.APPLICATION_JSON})
public Parameter performTest(Parameter in) {
System.out.println(in);
}
but the in always returns null. I can change #GET to #POST and it works but I'm not really performing an create or update so using post seems odd.
Is there a way to get the body with a GET request with jersey?
TL;DR The correct solution is to use POST.
"I can change #GET to #POST and it works but I'm not really performing an create or update so using post seems odd"
Why is that odd? POST is not limited to create/update operations.
The specification (RFC 7231, section 4.3.3. POST) says:
The POST method requests that the target resource process the representation enclosed in the request according to the resource's own specific semantics. For example, POST is used for the following functions (among others):
Providing a block of data, such as the fields entered into an HTML form, to a data-handling process;
Posting a message to a bulletin board, newsgroup, mailing list, blog, or similar group of articles;
Creating a new resource that has yet to be identified by the origin server; and
Appending data to a resource's existing representation(s).
To paraphrase, POST means "here's some data, please process it for me".
Sure, "process" often means "store", as in create/update, but that is not the only way to process data.
In your case, "process" means "run test, using these parameters".
Related
We have a proxy API set up where we accept any path after our proxy (i.e. /proxy/some/path) and then everything after the proxy path should be forwarded on to another API using RESTeasy (so it would call /some/path in my example).
This is necessary for us for several reasons including avoiding CORS issues and it works most of the time for what we need. However, some routes require query parameters some or all of the time, and because we are handling all routes the same, this causes a RESTeasy error today since the URL gets URL encoded to something like /some/path%3ffilter=value.
Our endpoint today looks like:
#Path("proxy/{someUri : .*}")
#GET
public Response proxyGet(
#PathParam("someUri") String someUri,
#HeaderParam(COOKIE) String cookieHeader,
#Context HttpServletRequest request
) {
return prepareProxyResponse(someUri, cookieHeader, request, null);
}
Our RESTeasy interface looks like:
#GET
#Path("/{requestPath}")
Response proxyGet(
#PathParam("requestPath") String requestPath,
#HeaderParam(COOKIE) String sessionCookie,
#HeaderParam(CONTENT_TYPE) String contentType
);
The code that calls this looks like:
return client.proxyGet(fullPath, cookieHeader, contentTypeHeader);
Prior to understanding this issue, we just took the request URI and added the query string to it so the requestPath above looked like some/path?filter=value which gets mangled. Removing the query string avoids that, however, it also means we cannot pass any query params through.
Is there a way to accept any query params and submit them to the other API using RESTeasy? I know we can break these out where needed to manually specify query params with #QueryParam but since there are many (and more getting added regularly) this will be a lot of effort. I think accomplishing what we are trying to do is not possible based on my research in other questions and the docs, but wanted to double-check before we embarked on a long process to convert. Thanks!
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.
I'm trying to create a REST API following the HTTP method semantics but I got stuck with the DELETE method.
In my use case, the service is behind a gateway that authenticates the user. This service uses a SSO token that then is used to authenticate the user and get his details. From this point, I'm trying to make a call to my service where I use the id of the resource I want to delete as a path variable but then I don't know how to pass the id of the user for validation.
I've read many posts about the problems of adding a body to a DELETE method. I also think adding a custom header to identify the user is not the right way. Out of the options I have, I think only 2 are sensible:
Issue a POST request with the user id as the body. I don't like this one because I'm basically using POST with an identified resource and because semantically sounds wrong to me.
Make the request so the user id is a path variable. It would look like this. path/to/service/resourceId/{resourceId}/userId/{userId}. My problem with this one is that in the POST and PUT requests, the userId is part of the body. The API wouldn't look consistent but I guess I could still change the other 2 so the user id is also part of the url.
Any suggestions?
You should use HTTP header param for passing user token.
#DELETE
#Path("/{id}")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public Info deleteInfo(
#HeaderParam("Authorization") String token,
#PathParam("id") Long id){
}
HTTP authentication, maybe? That's what it is for, no? See RFC 7235.
I'm using Jersey 2.19 to implement a REST API.
I'd like to know how I find out from the Jersey user guide or other specification how I'm supposed to know what the signature of my JAX-RS resource should be.
E.g. for a resource that handles POST requests I've experimented with the following different signatures using examples I've found.
public Response myResource()
public Response myResource(String param)
Both of these are valid in that they compile and run and the method is called under the right conditions.
Can anyone tell me where it is specified what the signatures should be and what the parameters mean? It seems like a straightforward question but I can't find the answer.
As you are saying its a POST request , so it should recieve some data from the Request. So you should expect something in Parameter.
public Response myResource(String param)
But the type of parameter should depend upon actually #Consumes annotation like :-
#Consumes(MediaType.APPLICATION_JSON) : This expects a JSONinput OR
#Consumes(MediaType.APPLICATION_XML) : This expects a XMLinput OR
#Consumes(MediaType.TEXT_PLAIN) : This expects a String plain text input
You annotate your Methods like described in the official documentation.
Also, do not forget to annotate the service-class with #Path
#Path("MyService")
public class MyService
{
#GET
#Produces(MediaType.APPLICATION_JSON)
#Path("/User")
public List<User> getUser()
{
//Return all users
}
//Inserts new User in JSON Format
#Get
#Path("/User/UserId/{userid}")
public User getUserById(#PathParam("userid") String userid)
{
//Find User with ID in Database and return it
}
#POST
#Consumes(MediaType.APPLICATION_JSON)
public User getUserById(User user)
{
//add user to your Database or something
}
}
If you now want to get all users in json format you have to call:
http://ip-address/MyService/user
There is an exact answer to your question, but gird your loins. Because if the Jersey docs are overly vague these are in the extreme opposite direction: written by someone showing off their PhD in abstract algebra it looks to me.
The answer to everything is in the JAX-RS spec, of which Jersey is an implementation. You can download it here as PDF (after you sign away your soul)
The specific answer to how one of those methods is selected instead of the other, is too detailed for me to paste in here, but it's under section "3.7.2 Request Matching"
I won't even try to paste in the mathematical rules used to set up the list of potential methods to match a request, then select from among them. There's no chance of getting them formatted readably in SO.
For your more general questions, the section "3.3 Resource Methods" is much more accessible. Here are a few choice excerpts:
3.3 Resource Methods
...
JAX-RS defines a set of
request method designators for the common HTTP methods: #GET, #POST,
#PUT, #DELETE, #HEAD and #OPTIONS.
...
3.3.1 Visibility: Only public methods may be exposed as resource methods.
...
3.3.2 Parameters: Resource methods MUST have at most one entity parameter ...
3.3.3 Return Type: Resource methods MAY return void, Response, GenericEntity, or another Java type...
etc, etc.
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.