Custom validation message in Grails

Grails1 is an awesome full stack, web application framework on JVM. It has good documentation but not excellent documentation. I am working on a business project where I am using Grails REST services with MongoDB as the backend. I will cover that setup in another blog post but this one is for providing information about setting up validation in Grails with custom validation messages.

Some background about Domain objects in Grails:

Often we have requirements where certain fields in the request need to have certain values. In other words, we need to validate the data in the incoming request. Grails provides constraints2 on domain and validatable3 objects. Below is an example.

package com.javawithravi.bookstore

class Book {  
    String title
    String description

    static constraints = {
        title nullable: false, blank: false, size: 10..50
        description nullable: false, blank: false, size: 100..500
    }
} 

For example: #9 above states that title cannot be:
1. empty
2. null or
3. less than 10 chars or more than 50 chars in length.

One line and you are done with constraints on title property. No need to write custom validation logic (not that you can't write custom constraint in Grails but you are provided with some common constraints out of the box).

Default messages for constraint violation:

Now, Grails comes with default messages.properties that provides default validation message(s) for each of the in-built constraints. A few examples:

default.invalid.min.message=Property [{0}] of class [{1}] with value [{2}] is less than minimum value [{3}]  
default.invalid.max.size.message=Property [{0}] of class [{1}] with value [{2}] exceeds the maximum size of [{3}]  
default.invalid.min.size.message=Property [{0}] of class [{1}] with value [{2}] is less than the minimum size of [{3}]  

So if you provide a title less than 10 chars long then you will get a message like:
Property [title] of class [com.javawithravi.bookstore.Book] with value [Yo] is less than the minimum size of [10]

Custom constraint message:

Pretty decent. But not very user friendly. So here's the good news. You can provide your own custom message for each domain class's constraint(s). To quote Grails doc:

If a constraint is violated Grails will by convention look for a message code of the form:

[Class Name].[Property Name].[Constraint Code]

Following the instructions above we can add lines below to messages.properties:

book.title.size.toosmall=Title should be less than [{3}] chars.  
book.title.size.toobig=Title cannot be greater than [{4}] chars.  

Okay, so the class name and property name is pretty intuitive. But what's not intuitive and isn't immediately clear and does not have easily accessible documentation is: what constraint code pertains to which constraint? Here's what you need to do: figure out the constraint you are using, go to that constraint's documentation [2] and get the constraint code from the section stating Error code. For example:

Name Constraint code Documentation Example
Min Size minSize.notmet http://grails.org/doc/latest/ref/Constraints/minSize.html children minSize: 25
Size size.toosmallsize.toosmall or size.toosmallsize.toobig http://grails.org/doc/latest/ref/Constraints/size.html book size: 5..15

NOTE: You have to use camel case for class and property name. For instance: blogPost.postTitle.size.toosmall=Yo, your blog post too small yo! ;-)

Sending custom constraint validation messages back to the user:

Once you validate a domain class (or a Validateable object), you can then access the constraint errors with object.errors for example: book.errors. And to access it in your controller you will do:

def jsonRequest = JSON.parse(request.JSON.toString())  
def book = new Book(jsonRequest)  
book.validate()  
if (book.hasErrors()) {  
    response.status = 422
    def errors = book.errors.allErrors.collect {
        message(error: it)
    }
    respond errors
}

The crucial lines are 6-8. Where you are iterating through all the errors on the book object and creating a list of messages using VaidationTagLib.message closure which is getting an instance of FieldError class. I had to scrounge through various blog sites 4 5 because I could not find documentation about how to access the custom message that was fully initiated!

Does this make sense? Did you find using custom constraints in Grails challenging? Thoughts? Feedback? NOTE: This is tested with Grails 2.4.4.


Reference:
  1. Grails documentation: http://grails.org/doc/latest/

  2. This is a pretty important resource and isn't linked anywhere easily accessible. Grails constraint documentation: http://grails.org/doc/latest/ref/Constraints/

  3. Grails documentation on Validation: http://grails.org/doc/latest/guide/validation.html

  4. This is where I started but this did NOT work with Grails 2.4.4: http://johnrellis.blogspot.com/2010/02/retrieve-grails-domain-errors-from.html

  5. Found my solution here: http://joshjustice.wordpress.com/2011/01/06/returning-grails-validation-errors-for-ajax-calls/