I'm using Jersey to create REST API. I have one POST method and as a response from that method, the user should be redirected to a custom URL like http://example.com that doesn't have to be related to API.
I was looking at other similar questions on this topic here but didn't find anything that I could use.
I'd suggest altering the signature of the JAX-RS-annotated method to return a javax.ws.rs.core.Response object. Depending on whether you intend the redirection to be permanent or temporary (i.e. whether the client should update its internal references to reflect the new address or not), the method should build and return a Response corresponding to an HTTP-301 (permanent redirect) or HTTP-302 (temporary redirect) status code.
Here's a description in the Jersey documentation regarding how to return custom HTTP responses: https://jersey.java.net/documentation/latest/representations.html#d0e5151. I haven't tested the following snippet, but I'd imagine that the code would look something like this, for HTTP-301:
#POST
public Response yourAPIMethod() {
URI targetURIForRedirection = ...;
return Response.seeOther(targetURIForRedirection).build();
}
...or this, for HTTP-302:
#POST
public Response yourAPIMethod() {
URI targetURIForRedirection = ...;
return Response.temporaryRedirect(targetURIForRedirection).build();
}
This worked for Me
#GET
#Path("/external-redirect2")
#Consumes(MediaType.APPLICATION_JSON)
public Response method2() throws URISyntaxException {
URI externalUri = new URI("https://in.yahoo.com/?p=us");
return Response.seeOther(externalUri).build();
}
Related
I'm new to REST and I'm making simple REST application with users and articles. I wonder what's the difference between two samples below:
#GetMapping("/user/{id}")
public User getUserById(PathVariable("id") String id) {
.....
return userService.getUserById();
}
and
#GetMapping("/user/{id}")
public ResponseEntity<User> getUserById(PathVariable("id") String id) {
.....
return new ResponseEntity<> ....
}
Which one is better to use?
And what's the main difference between two of them?
ResponseEntity is containing the entire HTTP response that returns as a response which gives the flexibility to add headers, change status code and do similar things to the response.
Another hand sending PJO class directly like returning users in the example is somewhat similar to return ResponseEntity.ok(user) which responded to user details successfully to the user. But the ability to change headers, status codes is not available if you return PJO directly.
It is good to use ResponseEntity over PJO when there is a scenario you need to change the headers or you need to change status according to the result.
eg: show not found when there is no data you can return ResponseEntity.status(404).body(<-body->).
at least in the Response Entity, you can set the http status and you can use ResponseEntity<?> where ? is generic any object its very convenient to use
I am trying to do a get call with request body(JSON) as the request parameter list exceeds the limit. I am able to send the request via postman/insomnia and request is reaching till controller without any error. But the "requstBody" is empty at controller. What i am missing here?
#GET
#Path("\path")
#Consumes(APPLICATION_JSON)
#Produces(APPLICATION_JSON)
public Response getResponse(String requestBody) throws IOException { }
When I replaced #GET with #POST, requestBody has value. For GET call do we need to add anything more?
I am trying to do a get call with request body(JSON) as the request parameter list exceeds the limit. I am able to send the request via postman/insomnia and request is reaching till controller without any error. But the "requstBody" is empty at controller. What i am missing here?
One thing you are missing is the fact that the semantics of a request body with GET are not well defined.
RFC 7231, Section 4.3.1:
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.
There are two ways for sending parameters in an Http Get method. PathVariable and RequestParam. In this way, sent parameters are visible in the request URL. for example:
www.sampleAddress.com/countries/{parameter1}/get-time?city=someValues
In the above request, parameter1 is a path variable and parameter2 is a request parameter. So an example of a valid URL would be:
www.sampleAddress.com/countries/Germany/get-time?city=berlin
To access these parameters in a java controller, you need to define a specific name for the parameters. For example the following controller will receive this type of requests:
#GetMapping(value = "/countries/{parameter1}/get-time", produces = "application/json; charset=utf-8")
public String getTimeOfCities(
#PathVariable(value = "parameter1") String country,
#RequestParam(value = "city") String city
){
return "the method is not implemented yet";
}
You are able to send RequestBody through a Get request but it is not recommended according to this link.
yes, you can send a body with GET, and no, it is never useful
to do so.
This elaboration in elasticsearch website is nice too:
The HTTP libraries of certain languages (notably JavaScript) don’t allow GET requests to have a request body. In fact, some users are suprised that GET requests are ever allowed to have a body.
The truth is that RFC 7231—the RFC that deals with HTTP semantics and
content—does not define what should happen to a GET request with a
body! As a result, some HTTP servers allow it, and some—especially
caching proxies—don’t.
If you want to use Post method, you are able to have RequestBody too. In the case you want to send data by a post request, an appropriate controller would be like this:
#PostMapping(value = "/countries/{parameter1}/get-time", produces = "application/json; charset=utf-8")
public String getTimeOfCitiesByPost(
#PathVariable(value = "parameter1") String country,
#RequestParam(value = "city") String city,
#RequestBody Object myCustomObject
){
return "the method is not implemented yet";
}
myCustomObject could have any type of data you defined in your code. Note that in this way, you should send request body as a Json string.
put #RequestBody on String requestBody parameter
#RequestMapping("/path/{requestBody}")
public Response getResponse(#PathVariable String requestBody) throws IOException { }
I have an API created with Jersey
There's currently an endpoint to which users can make POST requests. There is no body required, as all the information is in the url.
#POST
#Path("entries")
#Produces(MEDIATYPE_JSON_AND_XML)
public Response createEntry(){
...
}
A new, empty, entry is created and the id is returned.
Content-Type of the request doesn't matter, as there is no request body data.
Now it should also be possible to set specific fields of the new entry during the request, using FormData. For this request a body is necessary, and the Content-Type must be multipart/form-data.
So I've created a second function:
#POST
#Path("entries")
#Consumes("multipart/form-data");
#Produces(MEDIATYPE_JSON_AND_XML)
public Response createEntryWithParam(#FormDataParam('param') String param){
...
}
This second function works te send the parameter in the request. But by adding it, the first stops working.
Sending a request without Content-Type will throw a NullPointerException. Probably because the #Consumes triggers some kind of Content-Type-check, which fails.
Is there a way to have one endpoint accepting POST requests with or without request-body?
edit So, I would like to receive all multipart/form-data requests in the seconds function, and use the first as a kind of catch-all for other POST requests to that endpoint
Currently I have a work-around in place.
If a POST request comes in without MediaType (Content-Type) or request-body, I automatically add an empty JSON object and set the Content-Type accordingly.
#Provider
public class ContentTypeRequestFilter implements ContainerRequestFilter {
#Override
public void filter(ContainerRequestContext crc) throws IOException {
if (crc.getMethod().equals("POST") && crc.getMediaType() == null && crc.getLength() == -1){
crc.getHeaders().add("content-type", MediaType.APPLICATION_JSON);
InputStream in = IOUtils.toInputStream("{}");
crc.setEntityStream(in);
}
}
}
This works, but is kinda hacky in my opinion. I'm interested to know if there are better ways to achieve my desired result.
I have method like,
#POST
#Produces(MediaType.APPLICATION_XML)
#Consumes("text/plain")
public File addFile(String filePath){
return fileService.addFile(filePath);
}
And I am using "Postman rest client" for testing the post request and simply type a path like c:\myFile.txt in the raw section
but no String is passed to method, but when I hard-code the path it works
Is the problem from #consume ?
Please see the answer below
#POST
#Produces(MediaType.APPLICATION_XML)
#Consumes(MediaType.TEXT_PLAIN)
public File addFile(String filePath){
return fileService.addFile(filePath);
}
And the header content type
as text/plain while sending the request to server from postman
for your reference please see the image below
As stated above, there is no annotation to fetch the body of the request with Jax-RS ; The original definition of the service is correct.
The problem probably comes from postman settings.
You should select Body > raw > Text (text/plain).
Im trying to java webservices and trying to follow couple of tutorial examples.
In one of the example, I see #Produces annotation being used to specify the type of response that is being returned.
Example:
#GET
#Produces(MediaType.TEXT_PLAIN)
public String sayPlainTextHello() {
return "Hello Jersey";
}
but in another case, I see the Response object is being used as a Response...
Example:
#GET
#Path("/{param}")
public Response getMsg(#PathParam("param") String msg) {
String output = "Jersey say : " + msg;
return Response.status(200).entity(output).build();
}
Question:
Which is the correct way to send a response back - Response object or #Produces annotation?
When both scenarios can be used?
The best way is to use the combination of both, all the times. Here's why
#Produces basically defines the CONTENT-TYPE (MIME-TYPE) of the Response. But that is pretty much all. It does not define the HTTP Status codes (on error/success/server error etc). #Produces annotation just makes your life easier by not explicitly specifying WHAT the content-type would be in the Response.
Now why to use Response instead of "String" as the return type? Here's an example
Let's take the following code into consideration:
#GET
#Produces(MediaType.TEXT_PLAIN)
public String sayPlainTextHello() {
try
{
return someRemoteServerApi.getHelloString();
}
catch(exception ex)
{
return getErrorMessageString();
}
}
Now lets say that the remote server api failed to return back, which cased some kind of an error. NOW, you want to return an error back to the client ALONG with an error code (because frankly speaking, clients will only care for the error message string when developing. Once the client is developed, they will solely base their apis on the HTTP return status code).
So, in the above example, lets say you return an error json String such as (the getErrorMessageString()) :
{
"error":500
"message": "something went wrong"
}
BUT, your actual HTTP status code will still be "200 OK", because the Response is still a String and the response went through just fine. How would a client know if something went wrong in the apis? He will have to parse the json string (on error) and determine what went wrong.
Basically, in the above case, your success and failure BOTH will have the same HTTP status return code, which is not very helpful to the clients. Instead, the above code should change something like:
#GET
#Produces(MediaType.TEXT_PLAIN)
public Response sayPlainTextHello() {
try
{
return Response.status(200).entity(someRemoteServerApi.getHelloString()).build();
}
catch(exception ex)
{
return Response.status(500).entity(getErrorMessageString()).build();
}
}
Finally,
In regards to answering both your questions:
1) #Produces has nothing to do with WHAT kind of Response will be sent. It just sets the content-type on whatever Response object you will be sending. JAX-RS, by default, will put 200 OK response, unless ofcourse, an exception occurs that is uncaught. Then it will probably return 500. Basically, you will be relying on JAX-RS to return your error codes for you, which is not very good. You, as an implementer, should determine what kind of error codes and error messages should be sent to the client that are MOST meaningful
2) I will ALWAYS use Response as the return type of the method, along with #Produces and #Consumes annotations for each method. If you believe that your full resource (all methods in java resource class) is using the same #Produces and #Consumes mime-type (in most cases it's application/json) then you can define this at the class level itself, something along the lines of:
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
#Path("/rest/someResource")
public class MyResource()
{
#Path("/{resourceId")
#GET
public Response getResource(#PathParam("resourceId") String id)
{
doStuffAndReturnResponse();
}
}
This will, by default, apply the #produces and #consumes annotation to ALL the resource methods and if you want something specific on some specific resource method, you can override it by just providing the annotation for that specific method.
I hope I have explained it good enough! Happy coding!