Operation | REST method | Sample URI |
---|---|---|
Return item(s) | GET | /books (all books) /books/ (all books) /books/12 (one book with ID = 12) |
Create a new item | POST | (you pass the ID in the object itself) /books /books/ |
Update an item | PUT | (you pass the ID in the object itself) /books /books/ |
Delete an item | DELETE | /books/12 (book with ID = 12) |
PUT for update is very similar to POST for create. There are two differences and one of them will make this part interesting: one is that we pass the actual ID of the object to update (not really interesting), the other is the case when the object to update does not exist in the system (interesting as we will send 404 back to the user).
What happens if the object does not exist? We want to throw an exception, but a regular exception thrown and not caught while handling gives a 500 (Internal server error) on the client side. But that's not what we want. What do we want? Well, since the object was not found, we want to give the client a 404. But first, let's look at the controller.
Handling PUT with Spring MVC
@RequestMapping(value = "/books", method = RequestMethod.PUT) public BookTO handleBookUpdate(HttpServletResponse response, @RequestBody @Valid BookTO bookTO) { BooksBean booksBean = Factory.getBooksBean(); return booksBean.updateBook(bookTO); }
So, this is a sample action. As you can see, the RequestMapping value is identical to the one from the POST (create) action. Not a problem - the method is now PUT. We also have the RequestBody and Valid annotations known from the previous part.
OK, let's look at the Dojo part!
Handling PUT from the client perspective - Dojo
function updateBook(bookId, bookName) { var bookToUpdate = { "id":bookId, "name":bookName }; var actualContent = dojo.toJson(bookToUpdate); //Save. var deferred = this._request("rawXhrPut", { url: "http://localhost:8080/restsample-0.0.1-SNAPSHOT/rest/books.json", handleAs: "json", putData: actualContent, headers: { "Content-Type": "application/json"} }); deferred.addCallback(this, function(value) { alert("Updated! " + value.bookTO.id + ", " + value.bookTO.name); }); deferred.addErrback(this, function(value) { alert("Error: " + value); }); }
Nothing very cool here - except that we use Dojo rawXhrPut instead of xhrPut and putData instead of postData.
Throwing an exception that ends up as 404
Finally, let's look at the exception handling so that we get a 404.
@RequestMapping(value = "/books", method = RequestMethod.PUT) public BookTO handleBookUpdate(HttpServletResponse response, @RequestBody @Valid BookTO bookTO) throws IOException { BooksBean booksBean = Factory.getBooksBean(); try { return booksBean.updateBook(bookTO); } catch (BookNotFoundException e) { response.sendError(HttpServletResponse.SC_NOT_FOUND); return new BookTO(); } }
This code catches a BookNotFoundException. If the problem occurs, it writes a 404 to response and returns an empty object.
This is by no means perfect. An ideal way would be to be able to throw the exception without having to worry about writing a 404. This is something that perhaps Spring MVC could handle. I am not aware of such possibility.
Also, we return an empty object. This is definitely better than null, but it might be better to return an empty object more explicitly (a static EMPTY_BOOK field of an Empty final class - just an idea). It does not matter much in our case as client's processing will have to handle a 404 error anyway and will not even get to handle this empty object.
Why not just throw the exception and let the exception itself write a 404? I tried it and it does not work on JBoss (and it works perfectly on WebSphere), it turns out.
In the next and last part we will look at deleting.
Links
Download source code for this article
- REST with Spring 3.0, Spring MVC and Dojo. Part 1 - GET
- REST with Spring 3.0, Spring MVC and Dojo. Part 2 - GET from Dojo perspective
- REST with Spring 3.0, Spring MVC and Dojo. Part 3 - POST and JSR-303 validation
- REST with Spring 3.0, Spring MVC and Dojo. Part 4 - PUT (updating objects)
- REST with Spring 3.0, Spring MVC and Dojo. Part 5 - DELETE
No comments:
Post a Comment