Wednesday, August 14, 2013

Using REST with Grails - Quick and Dirty

Aim: To combine the RAD features of Grails with easy consumption of REST


Grails has been around for a bit and Grails 2.x is a great framework for rapid web application development. One of the things that might be a bit limiting is grails' use of server side gsp for the presentation layer. You know how everybody's grandmother, has an opinion about how the UI should be built, well...

That set me thinking, how about, if I wanted to leverage all the great feature of grails minus, its presentation layer, that is to say, how easily can I access grails server side from say HTML5/javascript framework or from android or iOS mobile app. Of course all that needs to be done, is to be able to invoke grails controllers from say javascript via REST calls.

So I started out with a default out of the box grails CRUD app with a POJO domain class called Item.

class Item {
static constraints = {    }
String name = "Item1";
String description = "Item1 Desc";
Date createdDate = new Date();

}

And I tried accessing the grails controllers from HTML/javascript/jquery. Seems you do it as easily as shown below:

For creating a new Item, all I need to do is a POST as seen below:
Notice the URL, HTTP verbs and $.param(myobj), which serializes, any javascript object attributes as HTTP request parameters

  //most of below object properties are same as grails domain POJO
var myobj = new Object();
myobj.createdDate = "date.struct";
myobj.createdDate_day = 13;
myobj.createdDate_month = 8;
myobj.createdDate_year = 2013;
myobj.description = "fromJSObject";
myobj.name = "fromJSObject";
myobj.create = "Create";

$.ajax({
 url: '/itemstore/item/save',
 type: 'POST',
 data: $.param(myobj),
 success: function(data) { alert('Insert was performed.');  }
});

On similar lines, we can do an update Item from jquery/javascript as follows

var myobj = new Object();
myobj.id = itemId;
myobj.version = 3;
myobj.createdDate = "date.struct";
myobj.createdDate_day = 13;
myobj.createdDate_month = 8;
myobj.createdDate_year = 2013;
myobj.description = "fromJSObjectUpdatedNew";
myobj.name = "fromJSObjectUpdatedNew";
myobj._action_update = "Update";

$.ajax({
 url: '/itemstore/item/edit/'+myobj.id,
 type: 'POST',
 data: $.param(myobj),
 success: function(data) { alert('Update was performed.');  }
});


Deleting an Item is as easy as:

var myobj = new Object();
myobj.id = itemId;
myobj._action_delete = "Delete";

$.ajax({
 url: '/itemstore/item/delete/'+myobj.id,
 type: 'POST',
 data: $.param(myobj),
 success: function(data) { alert('Delete was performed.');  }
});


The above way of invoking grails controllers is a bit of hack since, we did not modify the out of box or rather I should say "generated" controllers, which usually are geared up for server side invocation and have often have server side redirects. Sample grails controller server side code is shown below:

    def create() {
        [itemInstance: new Item(params)]
    }

    def save() {
        def itemInstance = new Item(params)
        if (!itemInstance.save(flush: true)) {
            render(view: "create", model: [itemInstance: itemInstance])
            return
        }

        flash.message = message(code: 'default.created.message', args: [message(code:        'item.label', default: 'Item'), itemInstance.id])
        redirect(action: "show", id: itemInstance.id)
    }


We were able to make do with shown jquery code because, we did not expect any return values from the controller invocations. Its always better to tweak the "generated" controller code, so that, it is oriented for REST, by commenting out the redirect and returning back either json objects as data or as validation messages.

But how about if we need some getters from the grails controller.Well, in such all you need to do is write your own little Grails controller with suitable methods.

Here I am showing the original controller code for a list() method returning all Items in database.

    def list(Integer max) {
        params.max = Math.min(max ?: 10, 100)
        [itemInstanceList: Item.list(params), itemInstanceTotal: Item.count()]
    }


And following is the slightly tweaked new method which will return JSON objects array

    def list(Integer max) {
        params.max = 100
render Item.list(params).encodeAsJSON()
    }

The significant difference is in calling the method groovy encodeAsJSON() and returning its result from the controller.

Next you have to add the following mapping to the UrlMappings.groovy file

"/restful/$controller/listall?"{
constraints {
         //maps the http verb GET to controller method list( )
action = [GET:"list"]  
}
}


Calling such a controller method from jquery/javascript is as easy as shown below:

$.getJSON("/itemstore/restful/item/listall", function(mydata) {
      
     // this will output valid JSON containing the array of Items we returned back
     console.log(mydata) 
});


Exposing grails controllers in such a fashion via REST or simply consuming them, in javascript, means you can have an alternative UI done in HTML5/javascript,, in a very short time.

Combining the RAD features of Grails with the ease of consumption of REST, is something truely valuable, wont you agree?


No comments: