Request Automatic Parsing in Grails

Grails comes with a parser that takes the request and parses it into variables – ‘params’ and ‘request’

Reading Url Params

The URL part is parsed into the ‘params’ variable. This includes the Url query string as well as URL-encoded string(body). Here is GET request initiated from Curl:
curl -G -d "title=Great%20Place" http://localhost:8010/minnehaha/review/update/100
So, at the controller to read Url parameters as follows:

//action in controller
def update() {
     params.id
     params.title
     params.action
     params.controller
...
}

Besides Url parameters, Grails parses also the ‘action’ and ‘controller’ for the given request

Reading Request Body

The body of the request is parsed into ‘request’ variable depending of ‘content-type’ specified in request. By default, the request parser supports two types – XML and JSON. Here is PUT request initiated via Curl:
curl -i -H "Content-Type: application/json" -X PUT -d '{"title":"great place"}' -d '{"content":"coming again soon"}' http://localhost:8010/minnehaha/review/update/100
At the controller, the request parser looks at the content-type, finds ‘json’ and parses into request.JSON:

..
request.JSON.title == 'great place'
request.JSON.content == 'coming again soon'
..

A common mistake is to forget specify ‘content-type’ in request resulting the ‘request.JSON’ variable to be empty because without the type, the parser is unable to parse request

The parser will always try to parse whenever there is a body attached to request even for GET and DELETE requests:
curl -i -H "Content-Type: application/json" -X GET -d '{"title":"great place"}' http://localhost:8010/minnehaha/review/update/100

By convention, the GET and DELETE requests doesn’t have raw/chunked body attached, however. HTTP/1.1 RFC does not forbids it and grails parser will parse it.

What if other than JSON or XML?

There may be situation where the data in body for the request is neither JSON nor XML format. To read the raw data:

request.getReader().text

However, this will give the following error:
getInputStream() has already been called for this request
This is because the default request parser needs to be turned off before reading the body text. Here is one way how to do it in the grails-app/conf/UrlMapping:

class UrlMappings {

    static mappings = {
        "/api/review/$id?"(controller: 'review', parseRequest: false){
            action = [ PUT: "update", POST: "save", GET: "show"]
        }
...
}

By specifying ‘parseRequests:false’ in highlighted line, it will turn off the Grails automatic parsing and make it possible to read the body data (i.e. request.getReader().text)

Content Negotiation

The Content Negotiation is topic in its own and should be separate post. Just to clarify, in the request header the ‘accept’ field is used for content negotiation and the ‘content-type’ is used for request parser to parse the body of request in Grails.

Useful Links:

  • http://grails.1312388.n4.nabble.com/Incoming-JSON-in-Controller-td4495260.html
  • http://grails.org/doc/2.2.x/ref/Controllers/withFormat.html
  • http://grails.org/doc/2.2.x/guide/single.html#contentNegotiation
  • http://jira.grails.org/browse/GRAILS-7099
  • http://grails.org/doc/1.3.9/ref/Servlet%20API/request.html
  • http://stackoverflow.com/questions/5905916/payloads-of-http-request-methods
  • http://sislands.com/coin70/week6/cgi.htm

2 thoughts on “Request Automatic Parsing in Grails

Leave a Reply

Your email address will not be published. Required fields are marked *