Music, software, life… and stuff.
[ Twitter ] [ GitHub ] [ Linked In ]
I am currently working on a set of JSON over HTTP web services APIs between Grails applications. Producing JSON content in Grails applications is ridiculously trivial, but the story on consuming content is not so clear.
I am using Tom Nichol’s HTTPBuilder for consumption. It’s a great library, but does take a little getting used to. Fortunately, the documentation is excellent.
HTTPBuilder ships with JSON support based on Andres Almiray’s json-lib. That works fine, but I was worried about a potential impedance mismatch between json-lib’s encoding/decoding and Grails’.
Here’s how I configured HTTPBuilder to use Grails’ JSON bits for encoding/decoding JSON data…
import groovyx.net.http.HTTPBuilder
import groovyx.net.http.ParserRegistry
import groovyx.net.http.ContentType.JSON
import org.apache.http.entity.EntityTemplate
import org.apache.http.entity.ContentProducer
import org.apache.http.message.BasicHeader
// create a builder instance
def builder = new HTTPBuilder()
// the closure that takes a HttpServletResponse and returns an object
def jsonParser = { response ->
grails.converters.JSON.parse(new InputStreamReader(response.entity.content, ParserRegistry.getCharset(response)))
}
// the closure that takes an object and returns an org.apache.http.HttpEntity
def jsonEncoder = { value ->
def json = value instanceof Closure ? new grails.web.JSONBuilder().build(value) : new grails.converters.JSON(value)
def producer = [writeTo: { OutputStream out -> out.withWriter { json.render(it) } }] as ContentProducer
def entity = new EntityTemplate(producer)
entity.contentType = new BasicHeader("Content-Type", JSON.toString())
entity
}
// for each JSON content type, install the handler
JSON.contentTypeStrings.each {
builder.parser."$it" = jsonParser
builder.encoder."$it" = jsonEncoder
}
Note that you have to configure each created HTTPBuilder instance.
Here is some contrived example usage. We are calling a JSON “mirror” service that simply just returns the JSON it was sent.
import grails.plugin.spock.*
import groovyx.net.http.Method.POST
import groovyx.net.http.ContentType.JSON
class HttpBuilderWithGrailsJsonSpec extends UnitSpec {
void "test it all works like it should"() {
given: "a configured HTTP builder"
def builder = new HTTPBuilder("http://jsonmirror.org")
// configure the builder as per above
when: "I post '{a: 1}' to the JSON mirror service"
def requestMethod = POST
def responseContentType = JSON
def result = builder.request(requestMethod, responseContentType) {
def requestContentType = JSON
send(requestContentType) {
a = 1
}
}
then: "I get the JSON '{a: 1}' returned"
result.a == 1
}
}
Posted: Feb 25th, 2010 @ 1:01 pm