Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

java webservice response object vs Produces

Tags:

java

jax-rs

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:

  1. Which is the correct way to send a response back - Response object or @Produces annotation?
  2. When both scenarios can be used?
like image 949
user1050619 Avatar asked Dec 06 '22 04:12

user1050619


1 Answers

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!

like image 152
shahshi15 Avatar answered Dec 20 '22 00:12

shahshi15