Search

Dark theme | Light theme
Showing posts with label GrailsGoodness:REST. Show all posts
Showing posts with label GrailsGoodness:REST. Show all posts

February 27, 2017

Grails Goodness: Custom JSON and Markup Views For Default REST Resources

In Grails we can use the @Resource annotation to make a domain class a REST resource. The annotation adds a controller as URL endpoint for the domain class. Values for the domain class properties are rendered with a default renderer. We can use JSON and markup views to customize the rendering of the domain class annotated with a @Resource annotation. First we must make sure we include views plugin in our build configuration. Then we must create a directory in the grails-app/views directory with the same name as our domain class name. Inside the directory we can add JSON and markup views with names that correspond with the controller actions. For example a file index.gson or index.gml for the index action. We can also create a template view that is automatically used for a resource instance by adding a view with the name of the domain class prefixed with an underscore (_).

In the next example application we create a custom view for the Book domain class that is annotated with the @Resource annotation:

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

import grails.rest.Resource

@Resource(uri = '/books')
class Book {
    
    String title
    String isbn
    
    static constraints = {
        title blank: false
        isbn blank: false
    }    
}

Next we must make sure the Grails views code is available as a dependency. In our build.gradle file we must have the following dependencies in the dependencies {} block:

// File: build.gradle
...
dependencies {
    ....
    // Support for JSON views.
    compile "org.grails.plugins:views-json:1.1.5"
    // Support for markup views.
    compile "org.grails.plugins:views-markup:1.1.5"
    ....
}
...

It is time to create new JSON views for JSON responses. We create the directory grails-app/views/book/ and the file _book.gson. This template file is automatically used by Grails now when a Book instances needs to be rendered:

// File: grails-app/views/book/_book.gson
import grails.util.Environment
import mrhaki.sample.Book

model {
    Book book
}

json {
    id book.id
    version book.version
    title book.title
    isbn book.isbn
    information {
        generatedBy 'Sample application'
        grailsVersion Environment.grailsVersion
        environment Environment.current.name
    }
}

We also create the file index.gson to support showing multiple Book instances:

// File: grails-app/views/book/index.gson
import mrhaki.sample.Book

model {
    List<Book> bookList  
} 

// We can use template namespace
// method with a Collection.
json tmpl.book(bookList)

If we also want to support XML we need to create extra markup views. First we a general template for a Book instance with the name _book.gml:

// File: grails-app/views/book/_book.gml
import grails.util.Environment
import mrhaki.sample.Book

model {
    Book book
}

xmlDeclaration()
book {
    id book.id
    title book.title
    isbn book.isbn
    information {
        generatedBy 'Sample application'
        grailsVersion Environment.grailsVersion
        environment Environment.current.name
    }
}

Next we create the file index.gml to show Book instances. Note we cannot use the template namespace in the markup view opposed to in the JSON view:

// File: grails-app/views/book/index.gml
import grails.util.Environment
import mrhaki.sample.Book

model {
    List<Book> bookList
}

xmlDeclaration()
books {
    bookList.each { bookInstance ->
        book {
            id bookInstance.id
            title bookInstance.title
            isbn bookInstance.isbn
            information {
                generatedBy 'Sample application'
                grailsVersion Environment.grailsVersion
                environment Environment.current.name
            }
        }
    }
}

We start our Grails application and use cUrl to invoke our REST resource:

$ curl -H Accept:application/xml http://localhost:8080/books/1
<?xml version='1.0' encoding='UTF-8'?>
<books>
    <book>
        <id>1</id><title>Gradle Dependency Management</title><isbn>978-1784392789</isbn><information>
            <generatedBy>Sample application</generatedBy><grailsVersion>3.2.6</grailsVersion><environment>development</environment>
        </information>
    </book><book>
        <id>2</id><title>Gradle Effective Implementation Guide</title><isbn>978-1784394974</isbn><information>
            <generatedBy>Sample application</generatedBy><grailsVersion>3.2.6</grailsVersion><environment>development</environment>
        </information>
    </book>
</books>

$ curl -H Accept:application/xml http://localhost:8080/books/1
<?xml version='1.0' encoding='UTF-8'?>
<book>
    <id>1</id><title>Gradle Dependency Management</title><isbn>978-1784392789</isbn><information>
        <generatedBy>Sample application</generatedBy><grailsVersion>3.2.6</grailsVersion><environment>development</environment>
    </information>
</book>

$ curl -H Accept:application/json http://localhost:8080/books
[
    {
        "id": 1,
        "version": 0,
        "title": "Gradle Dependency Management",
        "isbn": "978-1784392789",
        "information": {
            "generatedBy": "Sample application",
            "grailsVersion": "3.2.6",
            "environment": "development"
        }
    },
    {
        "id": 2,
        "version": 0,
        "title": "Gradle Effective Implementation Guide",
        "isbn": "978-1784394974",
        "information": {
            "generatedBy": "Sample application",
            "grailsVersion": "3.2.6",
            "environment": "development"
        }
    }
]

$ curl -H Accept:application/json http://localhost:8080/books/1
{
    "id": 1,
    "version": 0,
    "title": "Gradle Dependency Management",
    "isbn": "978-1784392789",
    "information": {
        "generatedBy": "Sample application",
        "grailsVersion": "3.2.6",
        "environment": "development"
    }
}
$

Written with Grails 3.2.6.

February 21, 2017

Grails Goodness: Using Domain Classes Without Persistence

Normally when we create a domain class in Grails we rely on GORM for all the persistence logic. But we can use the static property mapWith with the value none to instruct Grails the domain class is not persisted. This can be useful for example if we want to use a RestfulController for a resource and use the default data binding support in the RestfulController. The resource must be a domain class to make it work, but we might have a custom persistence implementation that is not GORM. By using the mapWith property we can still have benefits from the RestfulController and implement our own persistence mechanism.

In the following example we have a simple Book resource. We define it as a domain class, but tell Grails the persistence should not be handled by GORM:

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

import grails.rest.Resource

@Resource(uri = '/books', superClass= BookRestfulController)
class Book {
    
    static mapWith = 'none'
    
    String title
    String isbn
    
    static constraints = {
        title blank: false
        isbn blank: false
        
        // Allow to set id property directly in constructor.
        id bindable: true
    }
    
}

The application also has a Grails service BookRepositoryService that contains custom persistence logic for the Book class. In the following RestfulController for the Book resource we use BookRepositoryService and override methods of RestfulController to have a fully working Book resource:

// File: grails-app/controllers/mrhaki/sample/BookRestfulController.groovy
package mrhaki.sample

import grails.rest.RestfulController

class BookRestfulController extends RestfulController<Book> {
    
    BookRepositoryService bookRepositoryService
    
    BookRestfulController(final Class<Book> resource) {
        super(resource)
    }

    BookRestfulController(final Class<Book> resource, final boolean readOnly) {
        super(resource, readOnly)
    }

    @Override
    protected Book queryForResource(final Serializable id) {
        bookRepositoryService.get(Long.valueOf(id))
    }
    
    @Override
    protected List<Book> listAllResources(final Map params) {
        bookRepositoryService.all
    }

    @Override
    protected Integer countResources() {
        bookRepositoryService.total
    }

    @Override
    protected Book saveResource(final Book resource) {
        bookRepositoryService.add(resource)
    }

    @Override
    protected Book updateResource(final Book resource) {
        bookRepositoryService.update(resource)
    }

    @Override
    protected void deleteResource(final Book resource) {
        bookRepositoryService.remove(resource.id)
    }
}

Written with Grails 3.2.6.

April 24, 2015

Grails Goodness: Adding Health Check Indicators

With Grails 3 we also get Spring Boot Actuator. We can use Spring Boot Actuator to add some production-ready features for monitoring and managing our Grails application. One of the features is the addition of some endpoints with information about our application. By default we already have a /health endpoint when we start a Grails (3+) application. It gives back a JSON response with status UP. Let's expand this endpoint and add a disk space, database and url health check indicator.

We can set the application property endpoints.health.sensitive to false (securing these endpoints will be another blog post) and we automatically get a disk space health indicator. The default threshold is set to 10MB, so when the disk space is lower than 10MB the status is set to DOWN. The following snippet shows the change in the grails-app/conf/application.yml to set the property:

...
---
endpoints:
    health:
        sensitive: false
...

If we invoke the /health endpoint we get the following output:

{
    "status": "UP",
    "diskSpace": {
        "status": "UP",
        "free": 97169154048,
        "threshold": 10485760
    }
}

If we want to change the threshold we can create a Spring bean of type DiskSpaceHealthIndicatorProperties and name diskSpaceHealthIndicatorProperties to override the default bean. Since Grails 3 we can override doWithSpring method in the Application class to define Spring beans:

package healthcheck

import grails.boot.GrailsApp
import grails.boot.config.GrailsAutoConfiguration
import org.springframework.boot.actuate.health.DiskSpaceHealthIndicatorProperties

class Application extends GrailsAutoConfiguration {

    static void main(String[] args) {
        GrailsApp.run(Application)
    }

    @Override
    Closure doWithSpring() {
        { ->
            diskSpaceHealthIndicatorProperties(DiskSpaceHealthIndicatorProperties) {
                // Set threshold to 250MB.
                threshold = 250 * 1024 * 1024
            }
        }
    }
}

Spring Boot Actuator already contains implementations for checking SQL databases, Mongo, Redis, Solr and RabbitMQ. We can activate those when we add them as Spring beans to our application context. Then they are automatically picked up and added to the results of the /health endpoint. In the following example we create a Spring bean databaseHealth of type DataSourceHealthIndicator:

package healthcheck

import grails.boot.GrailsApp
import grails.boot.config.GrailsAutoConfiguration
import org.springframework.boot.actuate.health.DataSourceHealthIndicator
import org.springframework.boot.actuate.health.DiskSpaceHealthIndicatorProperties

class Application extends GrailsAutoConfiguration {

    static void main(String[] args) {
        GrailsApp.run(Application)
    }

    @Override
    Closure doWithSpring() {
        { ->
            // Configure data source health indicator based
            // on the dataSource in the application context.
            databaseHealthCheck(DataSourceHealthIndicator, dataSource)

            diskSpaceHealthIndicatorProperties(DiskSpaceHealthIndicatorProperties) {
                threshold = 250 * 1024 * 1024
            }
        }
    }
}

To create our own health indicator class we must implement the HealthIndicator interface. The easiest way is to extend the AbstractHealthIndicator class and override the method doHealthCheck. It might be nice to have a health indicator that can check if a URL is reachable. For example if we need to access a REST API reachable through HTTP in our application we can check if it is available.

package healthcheck

import org.springframework.boot.actuate.health.AbstractHealthIndicator
import org.springframework.boot.actuate.health.Health

class UrlHealthIndicator extends AbstractHealthIndicator {

    private final String url

    private final int timeout

    UrlHealthIndicator(final String url, final int timeout = 10 * 1000) {
        this.url = url
        this.timeout = timeout
    }

    @Override
    protected void doHealthCheck(Health.Builder builder) throws Exception {
        final HttpURLConnection urlConnection =
                (HttpURLConnection) url.toURL().openConnection()

        final int responseCode =
                urlConnection.with {
                    requestMethod = 'HEAD'
                    readTimeout = timeout
                    connectTimeout = timeout
                    connect()
                    responseCode
                }

        // If code in 200 to 399 range everything is fine.
        responseCode in (200..399) ?
                builder.up() :
                builder.down(
                        new Exception(
                                "Invalid responseCode '${responseCode}' checking '${url}'."))
    }
}

In our Application class we create a Spring bean for this health indicator so it is picked up by the Spring Boot Actuator code:

package healthcheck

import grails.boot.GrailsApp
import grails.boot.config.GrailsAutoConfiguration
import org.springframework.boot.actuate.health.DataSourceHealthIndicator
import org.springframework.boot.actuate.health.DiskSpaceHealthIndicatorProperties

class Application extends GrailsAutoConfiguration {

    static void main(String[] args) {
        GrailsApp.run(Application)
    }

    @Override
    Closure doWithSpring() {
        { ->
            // Create instance for URL health indicator.
            urlHealthCheck(UrlHealthIndicator, 'http://intranet', 2000)

            databaseHealthCheck(DataSourceHealthIndicator, dataSource)

            diskSpaceHealthIndicatorProperties(DiskSpaceHealthIndicatorProperties) {
                threshold = 250 * 1024 * 1024
            }
        }
    }
}

Now when we run our Grails application and access the /health endpoint we get the following JSON:

{
    "status": "DOWN",
    "urlHealthCheck": {
        "status": "DOWN"
        "error": "java.net.UnknownHostException: intranet",
    },
    "databaseHealthCheck": {
        "status": "UP"
        "database": "H2",
        "hello": 1,
    },
    "diskSpace": {
        "status": "UP",
        "free": 96622411776,
        "threshold": 262144000
    },
}

Notice that the URL health check fails so the complete status is set to DOWN.

Written with Grails 3.0.1.

July 11, 2014

Grails Goodness: Using Converter Named Configurations with Default Renderers

Sometimes we want to support in our RESTful API a different level of detail in the output for the same resource. For example a default output with the basic fields and a more detailed output with all fields for a resource. The client of our API can then choose if the default or detailed output is needed. One of the ways to implement this in Grails is using converter named configurations.

Grails converters, like JSON and XML, support named configurations. First we need to register a named configuration with the converter. Then we can invoke the use method of the converter with the name of the configuration and a closure with statements to generate output. The code in the closure is executed in the context of the named configuration.

The default renderers in Grails, for example DefaultJsonRenderer, have a property namedConfiguration. The renderer will use the named configuration if the property is set to render the output in the context of the configured named configuration. Let's configure the appropriate renderers and register named configurations to support the named configuration in the default renderers.

In our example we have a User resource with some properties. We want to support short and details output where different properties are included in the resulting format.

First we have our resource:

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

import grails.rest.*

// Set URI for resource to /users.
// The first format in formats is the default
// format. So we could use short if we wanted
// the short compact format as default for this 
// resources.
@Resource(uri = '/users', formats = ['json', 'short', 'details'])
class User {

    String username
    String lastname
    String firstname
    String email

    static constraints = {
        email email: true
        lastname nullable: true
        firstname nullable: true
    }

}

Next we register two named configurations for this resource in our Bootstrap:

// File: grails-app/conf/Bootstrap.groovy
class Bootstrap {

    def init = { servletContext ->
        ...
        JSON.createNamedConfig('details') {
            it.registerObjectMarshaller(User) { User user ->
                final String fullname = [user.firstname, user.lastname].join(' ')
                final userMap = [
                        id      : user.id,
                        username: user.username,
                        email   : user.email,
                ]
                if (fullname) {
                    userMap.fullname = fullname
                }
                userMap
            }
            // Add for other resources a marshaller within
            // named configuration.
        }

        JSON.createNamedConfig('short') {
            it.registerObjectMarshaller(User) { User user ->
                final userMap = [
                        id      : user.id,
                        username: user.username
                ]
                userMap
            }
            // Add for other resources a marshaller within
            // named configuration.
        }    
        ...
    }
...
}

Now we must register custom renderers for the User resource as Spring components in resources:

// File: grails-app/conf/spring/resources.groovy
import com.mrhaki.grails.User
import grails.rest.render.json.JsonRenderer
import org.codehaus.groovy.grails.web.mime.MimeType

beans = {
    // Register JSON renderer for User resource with detailed output.
    userDetailsRenderer(JsonRenderer, User) {
        // Grails will compare the name of the MimeType
        // to determine which renderer to use. So we 
        // use our own custom name here. 
        // The second argument, 'details', specifies the
        // supported extension. We can now use
        // the request parameter format=details to use
        // this renderer for the User resource.
        mimeTypes = [new MimeType('application/vnd.com.mrhaki.grails.details+json', 'details')]
        
        // Here we specify the named configuration
        // that must be used by an instance
        // of this renderer. See Bootstrap.groovy
        // for available registered named configuration.
        namedConfiguration = 'details'
    }

    // Register second JSON renderer for User resource with compact output.
    userShortRenderer(JsonRenderer, User) {
        mimeTypes = [new MimeType('application/vnd.com.mrhaki.grails.short+json', 'short')]

        // Named configuration is different for short
        // renderer compared to details renderer.
        namedConfiguration = 'short'
    }

    // Default JSON renderer as fallback.
    userRenderer(JsonRenderer, User) {
        mimeTypes = [new MimeType('application/json', 'json')]
    }

}

We have defined some new mime types in grails-app/conf/spring/resources.groovy, but we must also add them to our grails-app/conf/Config.groovy file:

// File: grails-app/conf/spring/resources.groovy
...
grails.mime.types = [
    ...
    short   : ['application/vnd.com.mrhaki.grails.short+json', 'application/json'],
    details : ['application/vnd.com.mrhaki.grails.details+json', 'application/json'],
]
...

Our application is now ready and configured. We mostly rely on Grails content negotiation to get the correct renderer for generating our output if we request a resource. Grails content negotiation can use the value of the request parameter format to find the correct mime type and then the correct renderer. Grails also can check the Accept request header or the URI extension, but for our RESTful API we want to use the format request parameter.

If we invoke our resource with different formats we see the following results:

$ curl -X GET http://localhost:8080/rest-sample/users/1
{
    "class": "com.mrhaki.grails.User",
    "id": 1,
    "email": "hubert@mrhaki.com",
    "firstname": "Hubert",
    "lastname": "Klein Ikkink",
    "username": "mrhaki"
}
$ curl -X GET http://localhost:8080/rest-sample/users/1?format=short
{
    "id": 1,
    "username": "mrhaki"
}
$ curl -X GET http://localhost:8080/rest-sample/users/1?format=details
{
    "id": 1,
    "username": "mrhaki",
    "email": "hubert@mrhaki.com",
    "fullname": "Hubert Klein Ikkink"
}

Code written with Grails 2.4.2.

July 9, 2014

Grails Goodness: Custom Controller Class with Resource Annotation

In Grails we can apply the @Resource AST (Abstract Syntax Tree) annotation to a domain class. Grails will generate a complete new controller which by default extends grails.rest.RestfulController. We can use our own controller class that will be extended by the @Resource transformation. For example we might want to disable the delete action, but still want to use the @Resource transformation. We simply write a new RestfulController implementation and use the superClass attribute for the annotation to assign our custom controller as the value.

First we write a new RestfulController and we override the delete action. We return a HTTP status code 405 Method not allowed:

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

import grails.rest.*

import static org.springframework.http.HttpStatus.METHOD_NOT_ALLOWED

/**
 * Custom RestfulController where we disable the delete action.
 */
class NonDeleteRestfulController<T> extends RestfulController<T> {

    // We need to provide the constructors, so the 
    // Resource transformation works.
    NonDeleteRestfulController(Class<T> domainClass) {
        this(domainClass, false)
    }

    NonDeleteRestfulController(Class<T> domainClass, boolean readOnly) {
        super(domainClass, readOnly)
    }

    @Override
    def delete() {
        // Return Method not allowed HTTP status code.
        render status: METHOD_NOT_ALLOWED
    }
    
}

Next we indicate in the @Resource annotation with the superClass attribute that we want to use the NonDeleteRestfulController:

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

import grails.rest.*

@Resource(uri = '/users', superClass = NonDeleteRestfulController)
class User {

    String username
    String lastname
    String firstname
    String email

    static constraints = {
        email email: true
        lastname nullable: true
        firstname nullable: true
    }

}

When we access the resource /users/{id} with the HTTP DELETE method we get a 405 Method Not Allowed response status code.

Written with Grails 2.4.2.

Grails Goodness: Change Response Formats in RestfulController

We can write a RESTful application with Grails and define our API in different ways. One of them is to subclass the grails.rest.RestfulController. The RestfulController already contains a lot of useful methods to work with resources. For example all CRUD methods (save/show/update/delete) are available and are mapped to the correct HTTP verbs using a URL mapping with the resource(s) attribute.

We can define which content types are supported with the static variable responseFormats in our controller. The variable should be a list of String values with the supported formats. The list of supported formats applies to all methods in our controller. The names of the formats are defined in the configuration property grails.mime.types. We can also use a Map notation with the supportedFormats variable. The key of the map is the method name and the value is a list of formats.

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

import grails.rest.*

class UserApiController extends RestfulController {

    // Use Map notation to set supported formats
    // per action.
    static responseFormats = [
        index: ['xml', 'json'],  // Support both XML, JSON
        show: ['json']           // Only support JSON
    ]

    // We make the resource read-only in
    // the constructor.
    UserApiController() {
        super(User, true /* read-only */)
    }

}

We can also specify supported formats per action using the respond method in our controller. We can define the named argument formats followed by a list of formats when we invoke the respond method. In the following controller we override the index and show methods and use the formats attribute when we use the respond method:

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

import grails.rest.*

class UserApiController extends RestfulController {

    // We make the resource read-only in
    // the constructor.
    UserApiController() {
        super(User, true /* read-only */)
    }

    @Override
    def index(Integer max) {
        params.max = Math.min(max ?: 10, 100)
        respond listAllResources(params), formats: ['xml', 'json']
    }

    @Override
    def show() {
        respond queryForResource(params.id), formats: ['json']
    }

}

Code written with Grails 2.4.2.

July 8, 2014

Grails Goodness: Enable Accept Header for User Agent Requests

Especially when we use Grails to create a RESTful API we want to enable the request header Accept, so Grails can do content negotiation based on the value in the header. For example we could use the request header Accept: application/json to get a JSON response. Grails will look at the boolean configuration property grails.mime.use.accept.header to see if the Accept header must be parsed. The default value is true so the Accept header is used. But there is another property which determines if the Accept header is used: grails.mime.disable.accept.header.userAgents. The value must contain a list or a regular expression pattern of user agents which are ignored for the Accept header. The default value is ~/(Gecko(?i)|WebKit(?i)|Presto(?i)|Trident(?i))/. So for any request from these user agents, mostly our web browser, the Accept header is ignored.

If we use REST web services test tools from our browser, for example Postman, then any Accept header we set in the tool is ignored by Grails. We must change the value of the configuration property grails.mime.disable.accept.header.userAgents to for example an empty list. Then we know for every request send to our Grails application, either from a web browser or command-line tool like curl, the Accept header is interpreted by Grails.

The following sample shows how we make sure the Accept header is always used:

// File: grails-app/conf/Config.groovy
...
grails.mime.use.accept.header = true // Default value is true.
grails.mime.disable.accept.header.userAgents = []
...

Written with Grails 2.4.1.

February 6, 2014

Grails Goodness: Customize Root Element Name Collections for XML Marshalling

When we convert a List or Set to XML using the Grails XML marshalling support the name of the root element is either <list> or <set>. We can change this name by extending the org.codehaus.groovy.grails.web.converters.marshaller.xml.CollectionMarshaller. We must override the method supports() to denote the type of collection we want to customize the root element name for. And we must override the method getElementName() which returns the actual name of the root element for the List or Set.

Let's first see the default output of a collection of Book domain classes. In a controller we have the following code:

package com.mrhaki.grails.sample

class SampleController {
    def list() {
        // To force 404 when no results are found
        // we must return null, because respond method
        // checks explicitly for null value and 
        // not Groovy truth.
        respond Book.list() ?: null
    }
}

The XML output is:

<?xml version="1.0" encoding="UTF-8"?>
<list>
  <book id="1" version="0">
    <author id="1" />
    <isbn>
      0451169514
    </isbn>
    <numberOfPages>
      1104
    </numberOfPages>
    <title>
      It
    </title>
  </book>
  <book id="2" version="0">
    <author id="1" />
    <isbn>
      0307743683
    </isbn>
    <numberOfPages>
      1472
    </numberOfPages>
    <title>
      The stand
    </title>
  </book>
</list>

To change the element name list to books we add the following code to the init closure in grails-app/app/BootStrap.groovy:

// File: grails-app/conf/BootStrap.groovy
import com.mrhaki.grails.sample.Book
import grails.converters.XML
import org.codehaus.groovy.grails.web.converters.marshaller.xml.CollectionMarshaller

class BootStrap {

    def init = { servletContext ->
        // Register custom collection marshaller for List with Book instances.
        // The root element name is set to books.
        XML.registerObjectMarshaller(new CollectionMarshaller() {
            @Override
            public boolean supports(Object object) {
                // We know there is at least one result, 
                // otherwise the controller respond method
                // would have returned a 404 response code.
                object instance of List && object.first() instance of Book
            }

            @Override
            String getElementName(final Object o) {
                'books'
            }
        })
    }
}

Now when we render a list of Book instances we get the following XML:

<?xml version="1.0" encoding="UTF-8"?>
<books>
  <book id="1" version="0">
    <author id="1" />
    <isbn>
      0451169514
    </isbn>
    <numberOfPages>
      1104
    </numberOfPages>
    <title>
      It
    </title>
  </book>
  <book id="2" version="0">
    <author id="1" />
    <isbn>
      0307743683
    </isbn>
    <numberOfPages>
      1472
    </numberOfPages>
    <title>
      The stand
    </title>
  </book>
</books>

To customize the XML marshaling output for Map collections we must subclass org.codehaus.groovy.grails.web.converters.marshaller.xml.MapMarshaller.

Code written with Grails 2.3.2

December 9, 2013

Grails Goodness: Rendering Partial RESTful Responses

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 includes and 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

November 21, 2013

Grails Goodness: Register Custom Marshaller Using ObjectMarshallerRegisterer

When we convert data to JSON or XML (or any other format actually) in our Grails application we can register custom marshallers. These marshallers must contain the logic to convert an input object to a given format. For example we could have a book class and we want to convert it to our own JSON format. We have different options in Grails to achieve this, but for now we will create a custom marshaller class CustomBookMarshaller. This class must implement the ObjectMarshaller<C> interface. The generic type is the converter the marshaller is for and is in most cases either grails.converters.XML or grails.converters.JSON. Next we must make sure Grails uses our custom marshaller and we must register it. In the Grails documentation is explained how to do this via grails-app/conf/Bootstrap.groovy where we invoke for example JSON.registerMarshaller(new CustomBookMarshaller()). Or via grails-app/conf/spring/resources.groovy where we must write an extra component with a method annotated @PostConstruct where JSON.registerMarshaller(new CustomBookMarshaller()) is invoked.

But there is also another way using org.codehaus.groovy.grails.web.converters.configuration.ObjectMarshallerRegisterer. This is a Spring bean just for configuring extra marshallers. The bean has a priority property we can use to define the priority for this marshaller. Grails will use a marshaller with the highest priority if for the same class multiple marshallers are defined. We can assign a marshaller to the marshaller property. And finally we must set the converter class, for example grails.converters.XML or grails.converters.JSON with the converter property.

In our grails-app/conf/spring/resources.groovy file we define a new instance of ObjectMarshallerRegisterer and assign the appropriate property values. The name of the bean in resources.groovy is not important, but we must make sure there is no name class with other Spring configured beans. Grails looks for all beans of type ObjectMarshallerRegisterer during marshaller configuration and use the information we provide.

// File: grails-app/conf/spring/resources.groovy
import com.mrhaki.json.CustomBookMarshaller
import grails.converters.JSON
import org.codehaus.groovy.grails.web.converters.configuration.ObjectMarshallerRegisterer

beans = {

    // The name is not important. The type is picked up 
    // by Grails and must be ObjectMarshallerRegisterer.
    customBookJsonMarshaller(ObjectMarshallerRegisterer) {
        // Assign custom marshaller instance.
        marshaller = new CustomBookMarshaller()

        // Set converter class type.
        converterClass = JSON

        // Optional set priority. Default value is 0.
        priority = 1
    }

}

Code written with Grails 2.3.2

November 20, 2013

Grails Goodness: Include Domain Version Property in JSON and XML Output

We can include the version property of domain classes in rendered JSON or XML output. By default the version property is not included in generated XML and JSON. To enable inclusion of the version property we can set the configuration property grails.converters.domain.include.version with the value true. With this property for both XML and JSON the version property is included in the output. To only enable this for XML we use the property grails.converters.xml.domain.include.version and for JSON we use the property grails.converters.json.domain.include.version.

The following snippet is from grails-app/conf/Config.groovy where the properties are defined:

...
// Include version for JSON generated output.
//grails.converters.json.domain.include.version = true

// Include version for XML generated output.
//grails.converters.xml.domain.include.version = true

// Include version for both XML and JSON output.
grails.converters.domain.include.version = true
...

The following samples show a representation of a book resources, which is a domain class and we see the version property as attribute of the book XML tag.

<?xml version="1.0" encoding="UTF-8"?>
<book id="1" version="0">
  <isbn>
    0451169514
  </isbn>
  <numberOfPages>
    1104
  </numberOfPages>
  <title>
    It
  </title>
</book>

In JSON the version is included as property.

{
  "class": "com.mrhaki.grails.sample.Book",
  "id": 1,
  "version": 0,
  "isbn": "0451169514",
  "numberOfPages": 1104,
  "title": "It"
}

Code written with Grails 2.3.2.

Grails Goodness: Pretty Print XML and JSON Output

If our Grails application renders XML or JSON output we can set configuration properties to enable pretty printing. This can be useful in for example in the development environment where we enable pretty printing and disable it for other environments. We set the configuration property grails.converters.default.pretty.print with the value true to enable pretty printing for both XML and JSON output. If we only want to pretty print XML we use the property grails.converters.xml.pretty.print and for JSON we use grails.converters.json.pretty.print.

First we look at the XML and JSON output when we don't enable pretty printing for a simple book resource:

<?xml version="1.0" encoding="UTF-8"?><book id="1"><isbn>0451169514</isbn><numberOfPages>1104</numberOfPages><title>It</title></book>
{"class":"com.mrhaki.grails.sample.Book","id":1,"isbn":"0451169514","numberOfPages":1104,"title":"It"}

Now we get the same book resource but with the following grails-app/conf/Config.groovy snippet:

...
environments {
    development {
        // Enable pretty print for JSON.
        //grails.converters.json.pretty.print = true

        // Enable pretty print for XML.
        //grails.converters.xml.pretty.print = true

        // Enable pretty print for JSON and XML.
        grails.converters.default.pretty.print = true
        ...
    }
}        
...

The following output shows how the representation is formatted nicely:

<?xml version="1.0" encoding="UTF-8"?>
<book id="1">
  <isbn>
    0451169514
  </isbn>
  <numberOfPages>
    1104
  </numberOfPages>
  <title>
    It
  </title>
</book>
{
  "class": "com.mrhaki.grails.sample.Book",
  "id": 1,
  "isbn": "0451169514",
  "numberOfPages": 1104,
  "title": "It"
}

Code written with Grails 2.3.2.

November 15, 2013

Grails Goodness: Customize Resource Mappings

Since Grails 2.3 it is very easy to define RESTful URL mappings for a controller. We can use the resources and resource attribute and use a controller name as the value. Grails will then automatically create a couple of URL mappings. Suppose we use the following mapping in grails-app/conf/UrlMappings.groovy: "/api/users"(resources: 'user'), then the following mappings are automatically created:

"/api/users/create"(controller: 'user', action: 'create', method: 'GET')
"/api/users/(*)/edit"(controller: 'user', action: 'edit', method: 'GET')
"/api/users(.(*))?"(controller: 'user', action: 'save', method: 'POST')
"/api/users(.(*))?"(controller: 'user', action: 'index', method: 'GET')
"/api/users/(*)(.(*))?"(controller: 'user', action: 'delete', method: 'DELETE')
"/api/users/(*)(.(*))?"(controller: 'user', action: 'update', method: 'PUT')
"/api/users/(*)(.(*))?"(controller: 'user', action: 'show', method: 'GET')

When we use the resource attribute to define a mapping like "/api/user"(resource: 'user') the following mappings are created by Grails:

"/api/user/create"(controller: 'user', action: 'create', method: 'GET')
"/api/user/edit"(controller: 'user', action: 'edit', method: 'GET')
"/api/user(.(*))?"(controller: 'user', action: 'delete', method: 'DELETE')
"/api/user(.(*))?"(controller: 'user', action: 'update', method: 'PUT')
"/api/user(.(*))?"(controller: 'user', action: 'save', method: 'POST')

Well there a lot of mappings created for us! But maybe we don't need all created mappings in our application. For example the mappings with /create and /edit are created by Grails to support also a UI variant for the controller actions, but we might want to leave them out when we only deal with JSON or XML payloads. We can use the includes and excludes attributes on the mapping to explicitly define which actions we want to support in our controller.

In the following sample UrlMappings.groovy configuration we exclude the create and edit actions in the first mapping. In the second mapping we only include the show and index actions:

// File: grails-app/conf/UrlMappings.groovy
import static org.codehaus.groovy.grails.web.mapping.DefaultUrlMappingEvaluator.*

import org.codehaus.groovy.grails.web.mapping.DefaultUrlMappingEvaluator

class UrlMappings {

    static mappings = {
        // Exclude the 'create' and 'edit' actions for the 
        // automatically created mappings.
        "/api/users"(resources: 'user', excludes: [ACTION_CREATE, ACTION_EDIT])

        // Include only the 'index' and 'show' actions for the 
        // automatically created mappings.
        "/api/products"(resources: 'product', includes: [ACTION_INDEX, ACTION_SHOW])
    }
}

Code written with Grails 2.3.