Customize Properties from RESTful Responses and Improve the RESTService API (Part 3)

In my previous two blogs, I wrote about creating a REST API in Grails 2.3.x and how to exclude properties from a REST response.
In this third blog about using REST in Grails 2.3.x, I show how to improve the used RESTService API by customizing the REST response.

This is the standard response of my RESTService:

{
  "class":"com.jolorenz.rest.City",
  "id":1,
  "cityName":"Munich",
  "countryCode":"DE",
  "dateCreated":"2014-02-28T04:24:13Z",
  "lastUpdated":"2014-02-28T04:24:13Z",
  "postalCode":"81927"
}

and this should become the customized response of the RESTService:

{
    "name of city": "Munich",
    "country of city": "DE",
    "last update": "11 Mrz 2014 19:42:40"
  }

As you see, the key and the value of the properties are customized.
So let’s see how to do it in Grails 2.3.x.

Custom Object Marshallers

The Grails documentation mentions the use of Custom Object Marshallers.
The steps outlined here follow almost strictly the docs.

Step 1: Create a Custom Object Marshaller

The custom object marshaller is a plain groovy class. You can create it in the /src/grooy directory with the appropriate package, e.g. com.jolorenz.rest.util.

package com.jolorenz.rest.util

import grails.converters.*
import com.jolorenz.rest.City

class CityMarshaller {
	@javax.annotation.PostConstruct
	void register() {
		log.info "Registering City Marshaller ..."
		JSON.registerObjectMarshaller (City) { City city ->
			def output = [:]
			output['name of city'] = city.cityName
			output['country of city'] = city.countryCode
			output['last update'] = city.dateCreated.format('dd MMM yyyy HH:mm:ss')
			return output;
		}
		log.info "Finished registering City Marshaller!"
	}
}

Step 2: Register the Custom Object Marshaller as Spring Bean

Modify /conf/spring/resources.groovy

// Place your Spring DSL code here
import package com.jolorenz.rest.util

beans = {
	cityMarshallerRegistrar(CityMarshaller)
}

You can name the spring bean as you like, just something meaningful. Grails will scan for all available beans.

According to the Grails doc, these two steps should be sufficient.
But if I did:

grails run-app

curl -X GET -H "Accept:application/json" http://localhost:8080/RESTService/api/city/1

the customizing was totally omitted.
While checking with the debugger, the CityMarshaller’s register() method was called. Also JSON.registerObjectMarshaller (City) {…} was registered during the startup of the Grails application, but the custom marshaller was never called again.
Even I followed the documentation closely, I am not sure, whether something is missed or is it a bug. So I decided to register the spring bean cityMarshallerRegistrar explicitly in the application’s spring context.

Step 3: Register the Spring Bean

Modify Bootstrap.groovy

import org.springframework.web.context.support.WebApplicationContextUtils

class BootStrap {
	def init = { servletContext ->
		...
		// Get spring context
		def springContext = WebApplicationContextUtils.getWebApplicationContext( servletContext )
		// register Custom Object Marshaller
		springContext.getBean( "cityMarshallerRegistrar").register()
                ...
        }
}

Restart your grails app again and run curl:

curl -X GET -H "Accept:application/json" http://localhost:8080/RESTService/api/city

Now you get the desired result:

[
  {
    "name of city": "Munich",
    "country of city": "DE",
    "last update": "11 Mrz 2014 19:31:41"
  },
  {
    "name of city": "Berlin",
    "country of city": "DE",
    "last update": "11 Mrz 2014 19:31:41"
  }
]J

Pretty cool and super easy!

Summary

Here I showed how to customize the response of the REST API by using a custom object marshaller.

HTH Johannes

Advertisements
This entry was posted in Development, Grails and tagged , , , . Bookmark the permalink.

9 Responses to Customize Properties from RESTful Responses and Improve the RESTService API (Part 3)

  1. Pingback: Logging HTTP Requests for better Debugging of the REST API (Part 4) | Coding Snippets

  2. Steffen says:

    Thanks, do you know how I can return different results based on the request so for example: /plannedevents => gives list with no details , /plannedevents/1 => gives detail from plannedevent

    • Hi Steffen,

      sorry for the late reply. You can use the same approach.
      Have a controller “PlannedEvent” and a dedicated “PlannedEventsController” (see the plural) with just a list method, e.g.

      def list() {
      def allPlannedEvents = PlannedEvent.list()
      respond allPlannedEvents
      }

      Then have a custom marshaller PlannedEventMarshaller and PlannedEventsMarshaller, e.g.

      class PlannedEventsMarshaller {
      @javax.annotation.PostConstruct
      void register() {
      JSON.registerObjectMarshaller (PlannedEvent) { PlannedEvent event ->
      def output = [:]
      output['event'] = event.name
      return output;
      }
      }
      }

      Register the custom marshaller as shown in the blog.
      Modify your URLMappings, e.g.

      "/plannedevents"(controller: "plannedEvents", parseRequest: true) {action = [GET: "list", POST: "save", PUT: "unsupported", DELETE: "unsupported"]}

      For the detail from a planned event, i would use “plannedevent/1” rather than “plannedevents/1”, and change URLMappings to

      "/plannedevent/$id"(resource: "plannedevent")

      I have not tried this code, just typed it from my memory but it should work, at least with some tweaking.

      HTH Johannes

  3. Alex Noria says:

    Where to implement the class CityMarshaller ? In which script ?

    Thanks

    • Hi Alex,

      thank your for your question. The post was indeed a little bit unclear about the custom object marshaller and I added the infos meanwhile.
      The custom object marshaller is a plain groovy class. You can create it in the /src/grooy directory with the appropriate package, e.g. com.jolorenz.rest.util.

      Your Johannes

      • Alex Noria says:

        Hi Johannes :

        /book/1 gives detail of the Book class, some ideas ?

        Thanks

  4. mmzen says:

    raaaaaahh thank you so much, I spent 2+ hours searching for why my marshaller wasn’t called even after registration as documented in grails latest documentation…

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s