Posts Tagged ‘json’

Streamlining JSON processing with Prototype 1.6

Saturday, February 9th, 2008

The other day I was doing some refactoring. I became aware that with Prototype 1.6, there comes a nice Ajax.Response object as the first argument of all Ajax callbacks. And as the documentation points out, the “responseJSON” property is “The JSON body of the response if the content-type of the request is set to application/json. null otherwise.”

I used to process the JSON responses from Grails the old way using the “response.responseText.evalJSON()” thing. So it looks like this process is nicely streamlined now. And now that I’ve replaced the stock prototype in Grails with the new 1.6 version, this is a low hanging fruit to make the code nicer. So why not?

In your Grails controller code, simply replace all occurrences of

render(contentType:"text/json", ...

With

render(contentType:"application/json", ...

And in your javascript, replace all

response.responseText.evalJSON()

with

response.responseJSON

Congratulations! Your code has just become one step more concise and prettier.

So here’s just a little tip I feel like sharing with you.

P.S. Grails 1.0 has been out a couple days now. Great news for all!

Mini guide to rendering JSON with Grails

Sunday, January 13th, 2008

Grails has built-in support for a JSON building DSL, which, together with the render controller dynamic method, makes rendering JSON responses an enjoyable job. But there seems to be a lack of consolidated information in the official documentation to clarify all the bits about getting anything you want in JSON. So here’s my little mini guide to share with you.

Ground Rules

As the JSON spec reads,

JSON is built on two structures:

  • A collection of name/value pairs. In various languages, this is realized as an object, record, struct, dictionary, hash table, keyed list, or associative array.
  • An ordered list of values. In most languages, this is realized as an array, vector, list, or sequence.

So there are only two rules for rendering JSON with Grails.

1. To render a collection of name/value pairs (an object), use the method call syntax.

e.g.

render(contentType:'text/json'){
	pair(name:'value')
}

Will be rendered as

{"pair":{"name":"value"}}

2. To render an array of values, use a closure

e.g.

render(contentType:'text/json'){
	collection{
		pair(name:'value')
		pair(name:'value1')
	}
}

Will be rendered as

{collection:[{"name":"value"},{"name":"value1"}]}

Anything inside the collection closure becomes the values of the array. And because of this, the method name “pair” has no place to appear in the rendered array.

Putting It to Work

Here’s an example putting the two rules together.

render(contentType:'text/json'){
	studio(name:'Pixar',website:'pixar.com')
	films{
		film(title:'Toy Story',year:'1995')
		film(title:'Monsters, Inc.',year:'2001')
		film(title:'Finding Nemo',year:'2003')
	}
}

The result JSON will be

{"studio":{"name":"Pixar","website":"pixar.com"},
"films":[
{"title":"Toy Story","year":"1995"},
{"title":"Monsters, Inc.","year":"2001"},
{"title":"Finding Nemo","year":"2003"}
]}

When DSL is Not Enough

But there’s a gotcha about the current JSON Builder DSL to keep in mind. As of 1.0 RC3, You can have objects inside an array, but not an array inside an object (except the JSON object itself).

For example, I want a JSON structure like this.

{"object":{"collection":[{"name":"value1"},{"name":"value2"}]}}

I may write something like this,

render(contentType:'text/json'){
	object(collection{
		item(name:'value1')
		item(name:'value2')
	})
}

Although it’s syntactically correct, you will get a runtime exception of

java.lang.IllegalArgumentException: JSON Builder: not implemented
	at grails.util.JSonBuilder.createNode(JSonBuilder.java:121)
...

Oh, maybe I made a mistake, I think. The closure is not a key/value pair there. And I change the code like this

render(contentType:'text/json'){
	object(collection:{
		item(name:'value1')
		item(name:'value2')
	})
}

This looks better. Does it work? Nope. It’s not what you’d expect.

{"object":{"collection":"DummyController$_closure15_closure27_closure28@4af40c"}}

This can’t be right. Then how about

render(contentType:'text/json'){
	object(collection:collection{
		item(name:'value1')
		item(name:'value2')
	})
}

Oddly, this will be rendered as

{"collection":[{"name":"value1"},{"name":"value2"}],"object":{"collection":1}}

The Almighty JSON converter

So is there any workaround, when JSON Builder DSL fails you? Yes! You can always turn to the JSON converter. Construct a temporary Map to contain the data, and use the converter to render the map as a whole.

To correctly render the JSON data in the previous section, you can use the JSON converter this way. In your controller, use the following code.

import grails.converters.*
...
def jsonMethod = {
	...
	def json = [object:[collection:[[name:'value1'],[name:'value2']]]]
	render json as JSON
}

The result JSON will be exactly what I want

{"object":{"collection":[{"name":"value1"},{"name":"value2"}]}}

You can render any object using the JSON converter. And the results are pretty predictable.

Performance-wise, I’m not sure if there’s any difference or anyone has done any benchmark yet. So I’d say that it’s really your call which way to make your JSON. The converter doesn’t look as sexy as the DSL, but it sure works great. I may just choose either one depending on my mood:)