Friday, April 23, 2010

Spring 3.0 Restful Web Services -- Flickr Style URLs

I just recently started to use the Spring Framework to create RESTful web services. We chose the Spring Framework because we are going to run in production with WebSphere v6.1 without any of the feature packs installed (ugh... one of these days maybe we'll get a modern application server) and WebSphere v6.1 didn't support the full J2EE spec for Java 1.5 when it was released. In order to support features like EJB 3.0 you must install the feature packs, but I digress.

Also, when I started to use the Spring Framework all of the RESTful web service tutorials used URL templates like the following where 1234233 is the index that identifies a particular book.

http://www.mydomain.com/books/1234233

However I wanted to do something like this:

http://www.mydomain.com?method=genInfo&bookId=1234233

I'm not sure why all of springs tutorials used the first style, but a lot of the RESTful web services that I looked into (ex: Flickr and Twitter) both support the second style.

So, with that being said, how do you create a class that allows you to use URL templates like Twitter.

@Controller
@RequestMapping(value = "/bookController.*")
public class BookController {
    @RequestMapping(value = "?method={method}&bookId={bookId}", params = {
"bookId"})
    public ModelAndView getBookDetails(
        @RequestParam("method") String method,
        @RequestParam("bookId") String bookId) {
        // business logic
    }
}

Please note the use of the @RequestParam attribute in the above example. You cannot use @PathVariable. Also, use params to help the system understand what is required or what shouldn't be there. In the following example I show how to tell the system that it shouldn't allow a particular argument.

@Controller
@RequestMapping(value = "/bookController.*")
public class BookController {
    @RequestMapping(value = "?method={method}&genre={genre}", params = {
"genre", "!publisherId"})
    public ModelAndView getBooksByGenre(
        @RequestParam("method") String method,
        @RequestParam("genre") String genre) {
            // busines logic
    }


    @RequestMapping(value = "?method={method}&genre={genre}&publisherId={publisherId}", params = {
"genre", "publisherId"})
    public ModelAndView getBooksByGenre(
        @RequestParam("method") String method,
        @RequestParam("genre") String genre, 
        @RequestParam("publisherId") String publisherId) {
            // busines logic
    }
}


From what I've found thus far if you have the code like above (pretty much allowing overloaded methods) you must tell the system not to execute the first method if it contains the publisherId parameter.  This is accomplished by using '!publisherId'.

More information about the use of params can be found at Stackoverflow and also in the javadoc for the @RequestMapping annotation.

No comments:

Post a Comment