Over a million developers have joined DZone.

Grails Goodness: Rendering Partial RESTful Responses

· Java Zone

Navigate the Maze of the End-User Experience and pick up this APM Essential guide, brought to you in partnership with CA Technologies

Grails 2.3 added a lot of support for RESTful services. For example we can now use a respond() method in our controllers to automatically render resources. The respond() method accepts a resource instance as argument and a map of attributes that can be passed. We can use the includesand excludes keys of the map to pass which fields of our resources need to be included or excluded in the response. This way we can render partial responses based on a request parameter value.

First we start with a simple domain class Book:

// File: grails-app/domain/com/mrhaki/grails/rest/Book.groovy
package com.mrhaki.grails.rest

class Book {

    String title
    String isbn
    int numberOfPages

}

Next we create a controller BookApiController, which we extend from the RestfulController so we already get a lot of basic functionality to render an instance of Book. We overwrite the index() and show() methods, because these are used to display our resource. We use the request parameter fields to define a comma separated list of fields and pass it to the includes attribute of the map we use with the respond() method. Notice we also set the excludes attribute to remove the class property from the output.

// File: grails-app/controllers/com/mrhaki/grails/rest/BookApiController.groovy
package com.mrhaki.grails.rest

import grails.rest.RestfulController

class BookApiController extends RestfulController<Book> {

    // We support both JSON and XML.
    static responseFormats = ['json', 'xml']

    BookApiController() {
        super(Book)
    }

    @Override
    def show() {
        // We pass which fields to be rendered with the includes attributes,
        // we exclude the class property for all responses.
        respond queryForResource(params.id), [includes: includeFields, excludes: ['class']]
    }

    @Override
    def index(final Integer max) {
        params.max = Math.min(max ?: 10, 100)
        respond listAllResources(params), [includes: includeFields, excludes: ['class']]
    }

    private getIncludeFields() {
        params.fields?.tokenize(',')
    }

}

Next we define a mapping to our controller in UrlMappings.groovy:

// File: grails-app/conf/UrlMappings.groovy

class UrlMappings {
    static mappings = {
...
        "/api/book"(resources: "bookApi")
...
    }
}

We are now almost done. We only have to register a new Spring component for the collection rendering of our Book resources. This is necessary to allow the usage of the includes and excludes attributes. These attributes are passed to the so-called componentType of the collection. In our case the componentType is the Book class.

// File: grails-app/conf/spring/resources.groovy

import com.mrhaki.grails.rest.Book
import grails.rest.render.json.JsonCollectionRenderer
import grails.rest.render.xml.XmlCollectionRenderer

beans = {
    // The name of the component is not relevant. 
    // The constructor argument Book sets the componentType for
    // the collection renderer.
    jsonBookCollectionRenderer(JsonCollectionRenderer, Book)
    xmlBookCollectionRenderer(XmlCollectionRenderer, Book)

    // Uncomment the following to register collection renderers
    // for all domain classes in the application.
    // for (domainClass in grailsApplication.domainClasses) {
    //     "json${domainClass.shortName}CollectionRenderer(JsonCollectionRenderer, domainClass.clazz)
    //     "xml${domainClass.shortName}CollectionRenderer(XmlCollectionRenderer, domainClass.clazz)
    // }
}

Now it is time to see our partial responses in action using some simple cURL invocations:

$ curl -X GET -H "Accept:application/json" http://localhost:9000/custom-renderers/api/book?fields=title
[
{
"title": "It"
},
{
"title": "The stand"
}
]
 
$ curl -X GET -H "Accept:application/xml" http://localhost:9000/custom-renderers/api/book?fields=title,isbn
<?xml version="1.0" encoding="UTF-8"?>
<list>
<book>
<isbn>
0451169514
</isbn>
<title>
It
</title>
</book>
<book>
<isbn>
0307743683
</isbn>
<title>
The stand
</title>
</book>
</list>
 
$ curl -X GET -H "Accept:application/json" http://localhost:9000/custom-renderers/api/book/1
{
"id": 1,
"isbn": "0451169514",
"numberOfPages": 1104,
"title": "It"
}
 
$ curl -X GET -H "Accept:application/json" http://localhost:9000/custom-renderers/api/book/1?fields=isbn,id
{
"id": 1,
"isbn": "0451169514"
}

Code written with Grails 2.3.2

Thrive in the application economy with an APM model that is strategic. Be E.P.I.C. with CA APM.  Brought to you in partnership with CA Technologies.

Topics:

Published at DZone with permission of Hubert Klein Ikkink, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

The best of DZone straight to your inbox.

SEE AN EXAMPLE
Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.
Subscribe

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}