Agile Ajax

Grails and JSONP: How Easy is That?

Grails_logo
For all of those Java developers casting longing glances at their buddies doing Rails development, there is hope. Grails, which has just celebrated its 1.0 release, is a Rails-like "convention over configuration" framework that aims to do for the Java world what Rails has done for Ruby. Instead of Ruby, the dynamic programming language of choice is Groovy, which compiles to bytecode (no Groovy to Java translation) and integrates smoothly with just about any Java code you may be using.

I'll stop hyping Groovy and Grails in general here; there's plenty of good informational stuff on the Grails and Groovy home pages. I will note that if you run off the tracks a little bit, you can find yourself reading through 500-odd line stack traces of Groovy, Spring and Hibernate -- there's room for some improvement there.

One of the many nice things about Grails is it's support for JSON and XML. Let me put together a simple example that shows off some of Grails' power.

In our example, we'll be entering rss feed titles and url's. We want to
be able to access those feed items as JSON, XML, XML wrapped in JSON,
JSONP and XML wrapped in JSONP. Whew! So, first things first, we will
create a grails app, then a domain class, then a controller.

% grails create-app[...output suppressed]% grails create-domain-class feed[...output suppressed]% grails generate-all feed[...output suppressed]

We edit the Feed.groovy class in grails-app/domain like so:


class Feed {
    String title
    String url
}

Sweet. Already we have an application that allows us to CRUD Feed items. Now how about some JSON and XML? Enter grails.converters.JSON and grails.converters.XML. We import these into our controller in grails-app/controllers/FeedController.groovy and tack on the following code:


import grails.converters.*

class FeedController {
[...]

def json = {
        def feed = Feed.get(params.id)

        if(!feed) {
            def error = ['error':"Feed not found with id ${params.id}."]
            render error as JSON
        } else {
            render feed as JSON
        }
    }

    def xml = {
        def feed = Feed.get(params.id)

        if(!feed) {
            def error = ['error':"Feed not found with id ${params.id}."]
            render error as XML
        } else {
            render feed as XML
        }
    }

    def jsonp = {
        def feed = Feed.get(params.id)

        if(!feed) {
            def error = ['error':"Feed not found with id ${params.id}."]
            render "${params.callback}(${error as JSON})"
        } else {
            render "${params.callback}(${feed as JSON})"
        }
    }

    def jsonpxml = {
        def feed = Feed.get(params.id)

        if(!feed) {
            def error = ['error':"Feed not found with id ${params.id}."]
            render "${params.callback}(${error as JSON})"
        } else {
            String xml = feed as XML
            def result = ['result':xml]
            render "${params.callback}(${result as JSON})"
        }
    }
}

That's it. Run it (grails run-app), enter some startup data and you can access it like so:

  • http://localhost:8080/JSONDemo/feed/json?id=1 -> {"id":1,"class":"Feed","title":"Ajaxian","url":"http://www.ajaxian.com/index.xml"}
  • http://localhost:8080/JSONDemo/feed/xml?id=1 ->
    <?xml version="1.0" encoding="ISO-8859-1"?><feed id="1">
      <title>Ajaxian</title>
      <url>http://www.ajaxian.com/index.xml</url>
    </feed>
  • http://localhost:8080/JSONDemo/feed/jsonp?id=1&callback=myFunc -> myFunc({"id":1,"class":"Feed","title":"Ajaxian","url":"http://www.ajaxian.com/index.xml"})
  • http://localhost:8080/JSONDemo/feed/jsonpxml?id=1&callback=myFunc -> myFunc({"result":"<feed id=\"1\">\n  <title>Ajaxian<\/title>\n  <url>http://www.ajaxian.com/index.xml<\/url>\n<\/feed>"})

Combine that
with all the other convention over configuration productivity
enhancements, and you wonder why you would want to develop JSON
backends in any other way.

Technorati Tags: , , , , ,

Comments: 1 so far

  1. Actually you can eliminate a lot of code in there if you use the “content negotiation” feature of Grails.

    It looks like this:

    import grails.converters.*
    class BookController {
    def books
    def list = {
    this.books = Book.list()
    withFormat {
    html bookList:books
    js { render “alert(’hello’)” }
    xml { render books as XML }
    }
    }
    }

    Read more about it if you like in the Grails reference docu: http://grails.org/doc/1.0.x/guide/6.%20The%20Web%20Layer.html#6.8%20Content%20Negotiation

    Comment by grandfatha, Tuesday, March 4, 2008 @ 1:38 am

Leave a comment

Powered by WP Hashcash

About Pathfinder

  • We design and build extraordinary applications for companies looking to make the next great idea a reality.
  • learn more

Topics

WordPress

Comments about this site: info@pathf.com