Tomás Lin’s Programming Brain Dump

Flex, Grails, Facebook, iPhone and all that Jazz

REST Service XML Output in Grails via Content Negotiation

with 5 comments

The content negotiation feature in Grails is pretty cool. In a nutshell, it allows you to return different formats based on the request of your page.

A recent project I worked on used Grail’s ability to generate CRUD as GSP pages to provide a basic CMS service, and an Adobe Flex front-end that communicated with Grails via REST services. We needed a solution that will preserve the original GSP html output, as well as the ability to return the data as XML for the REST layer.

Enabling the XMLfication of my components turned out to be dead simple with Grails. Here is what I did:

1. generate the templates by calling grails install-templates

2. open the file src/template/scaffolding/Controller.groovy

Add this line on the top:
import grails.converters.*

Modify the list command into :
 def list = {
        if(!params.max) params.max = 10
        withFormat{
            html{ [ ${propertyName}List: ${className}.list( params ) ] }
            xml(contentType:"text/xml"){ render ${className}.list( params ) as XML  }
        }
   }

Modify the show command to be 
    def show = {
        withFormat{
            html{
                def ${propertyName} = ${className}.get( params.id )
                if(!${propertyName}) {
                    flash.message = "${className} not found with id \${params.id}"
                    redirect(action:list)
                }
                else { return [ ${propertyName} : ${propertyName} ] }
            }
            xml(contentType:"text/xml"){ render  ${className}.get( params.id ) as XML }
        }
    }

Save the file. Now, every controller that I create will have the ability to render the response as an XML file, which I then parse with my FLEX front end using FLEX’s awesome e4x capabilities

Let’s say we now create a new class blah ( grails create-domain-class blah; grails generate-all blah ). You should see a html list when you do grails run-app and navigate to http://localhost:8080/myapp/blah/list. However, if you call http://localhost:8080/myapp/blah/list.xml or http://localhost:8080/myapp/blah/list?format=xml, you will get an XML result

Let me break that down a bit, the Grails withFormat command parses our request headers for us, and when I call list.xml, it uses that URI to resolve into the right format.  The grails converters then enable to return the output as XML. Simple, elegant and really really cool.

You can even go further, and add new formats with something like

withFormat{
    json(){ render ${className}.list(params) as JSON }
}

or even create new RSS feeds with the Feeds Plugin with something like

    rss(){ render(feedType:"rss", feedVersion:"2.0") ... 

( see this section for how to do this )

For our project, we only needed to do a display of the objects in XML, but the Grails documentation shows how to do xml submission robustly and has better examples of error checking ( which we do in the client level, so not needed at the server level ). But hopefully this gives a good starting point on how to do REST in Grails.

Have I mentioned how much I love Grails yet?

Written by Tomas Lin

May 15, 2008 at 4:01 pm

5 Responses

Subscribe to comments with RSS.

  1. [...] writing most of our backend code in Grails. Grails has an incredible content negotiation feature (that I blogged about before). With Grails, we get a default scaffolding HTML page that gets generated pretty much for free. [...]

  2. [...] with the Content Negotiation features of Grails, this allows us to quickly communicate with a flex application without the need to the complex [...]

  3. Does this work with dynamic scaffolding? It doesn’t seem to. I tried your instructions (save for general-all) and it doesn’t seem to work. Doesn’t dynamic scaffolding read from src/templates/scaffolding/Controller.groovy? Here’s my modified code:

    http://rifers.org/paste/show/7711

    Doesn’t work in Firefox 3 or Safari on Leopard with Grails 1.0.3 and Java 5.

    Matt

    Matt

    July 21, 2008 at 4:51 am

  4. Yes, it seems that this is not supported by default scaffolding. You would have to dig in deeper in the way the default scaffolding reads templates or submit a JIRA

    Tomas Lin

    July 21, 2008 at 5:38 am

  5. [...] PHP, JSP, and the like–can get what they need in a uniform manner.  So, I found this article here which gave me a good start.  However, it was outdated insofar as content negotiation and the [...]


Leave a Reply