What to return for different HTTP methods in JAX-RS?

Viewed 218

I am practicing building RESTFUL API's using the RESTEasy implementation. But I am still a little bit confused about what should I return according to the HTTP method. This is the way that I am doing it for the moment:

  1. @GET returns an Entity
  2. @POST returns an HTTP response with the actual entity created
  3. @PUT returns an HTTP response with the actual entity updated
  4. @DELETE returns an HTTP response with the actual entity deleted

Here is an example of my controller for illustration.

@GET
@Path("/{bookId}")
@Produces(MediaType.APPLICATION_JSON_VALUE)
public Book getBookById(@PathParam("bookId") Integer bookId) {
    return bookService.getBookById(bookId);
}

@POST
@Consumes(MediaType.APPLICATION_JSON_VALUE)
@Produces(MediaType.APPLICATION_JSON_VALUE)
public Response inertBook(@Valid Book book) {
    return bookService.insertBook(book);
}

@DELETE
@Path("/{bookId}")
public Response deleteBook(@PathParam("bookId") Integer bookId) {
    return bookService.deleteBook(bookId);
}

@PUT
@Path("/{bookId}")
@Consumes(MediaType.APPLICATION_JSON_VALUE)
@Produces(MediaType.APPLICATION_JSON_VALUE)
public Response updateBook(@PathParam("bookId") Integer bookId, @Valid Book book) {
    return bookService.updateBook(bookId, book);
}
2 Answers
  1. GET - The client is trying to retrieve a resource or in other words, get a resource. So yes, you should return an entity with a status code of "200 OK" In most cases, it will either be a single resource or a collection resource; in your example, either a single book or all of the books

  2. POST - When you create a new resource, generally the client will send the representation of the new book to be created. What the client doesn't have is the identifier for the resource or how to access the resource later. What is generally done is a Location header is sent back to the client so the client can later access the resource. The status of this response should be "201 Created" Optionally, you can send back the same representation the client sent, but including the newly created identifier. You can see an example in this post.

  3. PUT - This is a complete update. So whatever the client sends completely overwrites the current resource (excluding the identifier). So ultimately, the client has all the information already; no need to send anything back. You can just respond back with a "204 No Content" status. In code terms, you can simply have a void method or return a Response to explicitly set the status.

  4. DELETE - If everything goes well with the delete, there is no need to send anything but to let the client know that everything is OK. So simply sending a "200 OK" response is suitable. Optionally, including the deleted representation may be OK.

These are very general guidelines. Everyone has their own style, but most try to follow standards. Below are some resources you can dig into to learn more

Aside

I was looking at how your service layer implementation (your BookService class) and there are some design flaws. Generally, in a tiered application, the lower tiers should not know anything about the tier above it. Here is an example of tiers

  WEB
   ↓
SERVICE
   ↓
  DAO
  • The WEB layer is the REST layer (the JAX-RS code)
  • The SERVICE layer is the BookService where the business happens
  • The DAO layer is data later where data access happens

In this architecture, the DAO layer should not know about the SERVICE layer and SERVICE layer should not know about the WEB layer. In your example though, your service knows about Response objects. The Response should be only used in the WEB layer. A better implementation might look something like

public Response getBook(@PathParam("id") long id) {
    Book book = bookService.findBook(id);
    if (book == null) {
        throw new NotFoundException();
    }
    return book;
}
  

Now the BookService only has the responsibility of finding the book and the resource method handles all of the web logic.

Read about Entity Providers, they implement MessageBodyWriter.

RESTEasy is an implementation of JAX-RS (today, a sub-specification of Jakarta EE). In order to understand how the response is generated (which is what you need to know when thinking about what your resource methods can return), you should understand how the MessageBodyWriter works.

Resource Method can return almost anything, including String, Response, some custom bean, etc., but it's not that much about what your method returns, it's rather how(as which MediaType) your MessageBodyWriter implementation converts output stream into HTTP response body.

Value returned from the JAX-RS resource method is converted into an HTTP response body by an Entity Provider (that is a MessageBodyWriter implementation), and depending on what you instruct your method to set as a MIME type (with @Produces, on top of method) of the response and whether or not you have a corresponding converter (Entity Provider, i.e. MessageBodyWriter) on your classpath, JAX-RS will:

  1. look for the @Produces value;
  2. then look for the corresponding converter / MessageBodyWriter (will throw a conversion exception if no required implementation found on classpath);
  3. serialize your output stream into whatever you instruct it to return with @Produces(MediaType.TypeHere), and will return it.

Remember, that returning a non-void Java type results in a 200 OK response, while a void method results in a 204 No Content response.

@Produces specifies MIME type of response body, that your resource method should produce, by adding a Content-type header to the response. For different MIME types, you will need a corresponding converter library (implementation of MessageBodyWriter) to return whatever you're indicating as your Media/MIME type.

A side-note: JAX-RS is a specification for RESTful web services, which implies, that in most of the cases, you better work with JSON.

Related