Loading...

Friday, 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.

Wednesday, 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.

Tuesday, 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.

Thursday, July 3, 2014

Awesome Asciidoc: Escape Attribute References

One of the many cool features of Asciidoc is attribute substitution. We can define attributes with values and in our Asciidoc markup we reference those attributes between curly braces. For example we could include the value of the attribute customAttr like this in Asciidoc: {customAttr}. But sometimes we simply want to include some text between curly braces without any attribute value substitution. We need to put an escape character (\) before the first brace and Asciidoc will not replace the attribute with a value.

Suppose we have the following Asciidoc, where we want to explain some Groovy syntax ("${sampleValue}"). Asciidoc will try to substitute the attribute sampleValue with a value if set.

This is a sample where we include +"${}"+ as a Groovy GString sample. 
The sample +"${attrValue}"+ should be unchanged in the output.

If we generate HTML with Asciidoctor we get the following output and notice that attrValue is changed to attrvalue (lower case v):

If we add the escape character no attribute substitution will take place, even if we assign a value to the attribute attrValue:

:attrValue: sample

This is a sample where we include +"${}"+ as a Groovy GString sample. 
The sample +"$\{attrValue}"+ should be unchanged in the output.

Now we get the output we expect:

Written with Asciidoctor 0.1.4.

Wednesday, June 25, 2014

Awesome Asciidoc: Keep Line Breaks in Paragraphs

Normally when we write a paragraph in Asciidoc markup the line breaks are not preserved. Multiple lines are combined into a paragraph until an empty line is found to separate paragraphs. If we want to keep line breaks we must add the plus sign (+) at the end of the line. If we generate HTML from the Asciidoc markup a line break is inserted with a <br> tag. We can also use the hardbreaks document attribute to enable or disable line breaks in paragraphs without the addition of the + symbols.

In the following Asciidoc sample we use the + sign to keep line breaks in a paragraph:

// Use + to keep line breaks in paragraph.
A sample paragraph +
with line breaks +
applied using the _+_ symbol.

A sample paragraph 
without line breaks,
because the _+_ symbol 
is not used.

We get the following result if we use the HTML backend:

We can also use the hardbreaks attribute:

:hardbreaks:

A sample paragraph 
with line breaks.
Although the _+_ symbol 
is not used, but the
document attribute 
*:hardbreaks:* is set.

// Disable hardbreaks for reminder of document.
:!hardbreaks:

If we generate HTML we get the following result:

Samples written with Asciidoctor 0.1.4.

Spocklight: Write Our Own Data Provider

We can use data pipes to write data driven tests in Spock. A data pipe (<<) is fed by a data provider. We can use Collection objects as data provider, but also String objects and any class that implements the Iterable interface. We can write our own data provider class if we implement the Iterable interface.

In the following sample code we want to test the female property of the User class. We have the class MultilineProvider that implements the Iterable interface. The provider class accepts a multiline String value and returns the tokenized result of each line in each iteration.

package com.mrhaki.spock

@Grab('org.spockframework:spock-core:0.7-groovy-2.0')
import spock.lang.*

class ProviderSampleSpec extends Specification {

    @Unroll("Gender #gender for #name is #description")
    def "check if user is female or male based on gender value"() {
        given:
        def userData = '''\
            1;mrhaki;M;false
            2;Britt;F;true'''

        expect:
        new User(name: name, gender: gender).female == Boolean.valueOf(expected)

        where:
        [_, name, gender, expected] << new MultilineProvider(source: userData)

        // Extra data variable to be used in
        // @Unroll description.
        description = expected ? 'female' : 'not female'
    }

}

/**
 * Class under test. 
 */
class User {
    String name, gender

    Boolean isFemale() {
        gender == 'F'
    }
}

/**
 * Class implements Iterable interface so 
 * it can be used as data provider.
 */
class MultilineProvider implements Iterable {
    def source
    def lines
    def separator = ';'

    private int counter

    /**
     * Set multiline String as source 
     * and transform to a List of String
     * values and assign to the lines
     * property.
     */
    void setSource(source) {
        this.source = source.stripIndent()
        lines = this.source.readLines()
    }

    @Override
    Iterator iterator() {
        [
            hasNext: { 
                counter < lines.size() 
            },
            next: { 
                lines[counter++].tokenize(separator)
            }
        ] as Iterator
    }
}

Code written with Spock 0.7-groovy-2 and Groovy 2.3.3.

Spocklight: Assign Multiple Data Variables from Provider

We can write data driven tests with Spock. We can specify for example a data table or data pipes in a where: block. If we use a data pipe we can specify a data provider that will return the values that are used on each iteration. If our data provider returns multiple results for each row we can assign them immediatelly to multiple variables. We must use the syntax [var1, var2, var3] << providerImpl to assign values to the data variables var1, var2 and var3. We know from Groovy the multiple assignment syntax with parenthesis ((var1, var2, var3)), but with Spock we use square brackets.

In the following sample specification we have a simple feature method. The where: block shows how we can assign the values from the provider to multiple data variables. Notice we can skip values from the provider by using a _ to ignore the value.

package com.mrhaki.spock

@Grab('org.spockframework:spock-core:0.7-groovy-2.0')
import spock.lang.*

class MultiDataVarSpec extends Specification {

    @Unroll("#value as upper case is #expected")
    def "check upper case value of String"() {
        expect:
        value.toUpperCase() == expected

        where:
        // Multi data variables value and expected,
        // will be filled with elements from a row
        // on each iteration. The first element of each
        // row is ignored.
        // E.g. on first iteration:
        // value = 'abc'
        // and expected = 'ABC'
        [_, value, expected] << [
            [1, 'abc', 'ABC'],
            [2, 'def', 'DEF'], 
            [3, '123', '123']
        ]
    }


}

Code written with Spock 0.7-groovy-2.0 and Groovy 2.3.3.

Friday, June 20, 2014

Spocklight: Ignore Specifications Based On Conditions

We can use the @Ignore and @IgnoreRest annotation in our Spock specifications to not run the annotated specifications or features. With the @IgnoreIf annotation we can specify a condition that needs to evaluate to true to not run the feature or specification. The argument of the annotation is a closure. Inside the closure we can access three extra variables: properties (Java system properties), env (environment variables) and javaVersion.

In the following Spock specification we have a couple of features. Each feature has the @IgnoreIf annotation with different checks. We can use the extra variables, but we can also invoke our own methods in the closure argument for the annotation:

package com.mrhaki.spock

import spock.lang.*

class SampleRequiresSpec extends Specification {

    private static boolean isOsWindows() {
        System.properties['os.name'] == 'windows'
    }

    @IgnoreIf({ Boolean.valueOf(properties['spock.ignore.longRunning']) })
    def "run spec if Java system property 'spock.ignore.longRunning' is not set or false"() {
        expect:
        true
    }

    @IgnoreIf({ Boolean.valueOf(env['SPOCK_IGNORE_LONG_RUNNING']) })
    def "run spec if environment variable 'SPOCK_IGNORE_LONG_RUNNING' is not set or false"() {
        expect:
        true
    }

    @IgnoreIf({ javaVersion < 1.7 })
    def "run spec if run in Java 1.7 or higher"() {
        expect:
        true
    }

    @IgnoreIf({ javaVersion != 1.7 })
    def "run spec if run in Java 1.7"() {
        expect:
        true
    }

    @IgnoreIf({ isOsWindows() })
    def "run only if run on non-windows operating system"() {
        expect:
        true
    }

}

When we run our specification with Java 1.8 and do not set the Java system property spock.ignore.longRunning or we set the value to false and we do not set the environment variable SPOCK_IGNORE_LONG_RUNNING or give it the value false we can see that some features are ignored:

Now we run on Java 1.7, Windows operating system and set the Java system property spock.ignore.longRunning with the value true and the environment variable SPOCK_IGNORE_LONG_RUNNING with the value true. The resulting report shows the specifications that are ignored and those that are executed:

Code written with Spock 0.7-groovy-2.

Thursday, June 19, 2014

Awesome Asciidoc: Use Inline Icons

Asciidoctor adds the icon: macro to the Asciidoc markup. With the macro we can insert an icon in our text. We specify the name of the icon after the macro name. If we use an HTML backend together with the document attribute icons set to the value font we can use Font Awesome Icons. If we want to use icon images the icon is looked up in the directory specified by the attribute iconsdir. For example the Docbook backend will use this to insert an icon.

In the following markup we use the icon macro to insert a comment and file icon:

:icons: font

icon:comment[] This is a comment icon

icon:file[] And a file icon

We get the following result:

And the following HTML is generated:

<div class="paragraph">
<p><span class="icon"><i class="icon-comment"></i></span> This is a comment icon</p>
</div>

<div class="paragraph">
<p><span class="icon"><i class="icon-file"></i></span> And a file icon</p>
</div>

We can specify CSS classes using the role attribute for the macro. But together with the HTML backend and font-based icons we can also use other attributes: size, rotate and flip. The size attribute can specified without the attribute name if we use it as the first attribute:

// Change icon size
icon:comment[4x] This is a comment icon
// Alternative icon:comment[size="4x"]
// Possible values: large, 2x, 3x, 4x, 5x

// Flip and rotate
icon:file[flip="vertical", rotate="180", role="lime"] And a file icon
// Possible flip values: vertical, horizontal
// Possible rotate values: 90, 180, 270

When we generate HTML we get the following result:

When we want to use an inline icon as a link we can use the attributes link and window:

// Use link attribute to specify link.
// Optional window attribute will be the target window.
icon:user[link="http://www.mrhaki.com/about", window="_blank"]

Image based icons have the following attributes, like an image: alt, width, height, title, role.

Code written and generated with Asciidoctor 0.1.4.