Let’s use grails support on REST to offer a domain class and consume from a gsp using grooscript grails plugin. You can use groovy code in your gsp’s with grooscript tags. You can take a look at the source code of this demo in Github

You need grails 2.4+ installed in your system. Create a new project with > grails create-app rest-demo and move to created folder.

To install the grooscript grails plugin add to your BuildConfig.groovy:

plugins {
    ...
    compile ':grooscript:0.7'
    ...
}

Starting

Now let’s create a rest domain class, for example in grails-app/domain/rest/Book.groovy

package rest

import grails.rest.Resource

@Resource(uri='/books')
class Book {

    String title
    String author

    static constraints = {
        author nullable: true
    }
}

Now let’s add some books in BootStrap.groovy:

import rest.Book

class BootStrap {

    def init = { servletContext ->
        new Book(title: 'First Book').save()
        new Book(title: 'Second Book', author: 'some author').save()
    }
    def destroy = {
    }
}

And finally let’s see that books in the browser, changing grails-app/views/index.gsp:

<!DOCTYPE html>
<html>
<head>
    <title>Rest grooscript demo</title>
</head>
<body>
    <h2>List of books</h2>
    <g:each in="${rest.Book.list()}" var="book">
        <p>Title: ${book.title} - Author: ${book.author?:'unknown'}</p>
    </g:each>
</body>
</html>

Ok, now we have our application ready. Run the app > grails run-app and check that all is correct in your browser at http://localhost:8080/rest-demo. You must see the two book added in the bootstrap.

Grooscript list

Now let’s add grooscript grails support for rest domain classes. Then, we can work with our domain classes from the client, and save data in our server just saving our classes in the client side. First let’s change our view, and get the list of books from the client side.

<!DOCTYPE html>
<html>
<head>
    <title>Rest grooscript demo</title>
    <asset:javascript src="jquery.js"/> (1)
    <asset:javascript src="grooscript-grails.js"/> (2)
</head>
<body>
    <grooscript:remoteModel domainClass="Book"/> (3)
    <h2>List of books</h2>
    <div id="bookList"/>

    <grooscript:code> (4)
        import rest.Book

        def drawBooks = { (5)
            Book.list().then { list -> (6)
                $('#bookList').html ''
                list.each {
                    $('#bookList').append('<p>Title: '+it.title+' - Author: '+ (it.author?: 'unknown') +'</p>') (7)
                }
            }
        }

        $(document).ready {
            drawBooks() (8)
        }
    </grooscript:code>

    <asset:deferredScripts/> (9)
</body>
</html>
1 Need import jQuery to work with grooscript tags.
2 grooscript-grails.js is also needed, because contains grooscript.js and some helper utilities.
3 With this tag we can now use Book domain class in the client.
4 With this tag you can write groovy code that will be converted to javascript and will run in your browser.
5 Define function to draw a list of books using jQuery.
6 You can call domain methods as list, and you get a promise, with a then method that will run if all is ok.
7 Add books to the DOM.
8 Run drawBooks when the page is ready in tle client.
9 You have to add asset pipeline deferredScripts to process grooscript tags.

The difference between old code and the new code is that now, the render of the books is done in the client. This is the bigger change when you use grooscript tags. You are creating groovy code that is converted to javascript, and is running in the client side. The server now has less work to do. The conversion process is slower, but only is done 1 time in production, because it uses cache plugin.

When you insert groovy code in grooscript tags, don’t use ${}, because grails will try to process that code in the gsp.

The actions available with your rest domain class are: get(id), save() to create or update, list() to retrieve a list of objects, and delete(). You can use them as you use in your controller or services, but grooscript will return a promise of the result, because in the client an ajax call is done. The interface of the promise is the following, and fail closure is optional:

interface GsPromise {
    def then(Closure success, Closure fail)
}

Add books

I don’t wanna make this demo too long, and explain all grooscript and plugin stuff, but let’s add more functionality to this demo. Let’s add more books from the client. First let’s add inputs and the button:

<h3>Add a new book</h3>
<p>Title: <input type="text" id="title"></p>
<p>Author: <input type="text" id="author"></p>
<button type="button" onclick="addBook()">Add book</button>

Now let’s add the function to save the book in server database and add to list:

import rest.Book

def drawBooks = {
    Book.list().then { list ->
        $('#bookList').html ''
        list.each {
            appendBookToList(it)
        }
    }
}

def appendBookToList = { book ->
    $('#bookList').append('<p>Title: '+book.title+' - Author: '+ (book.author?: 'unknown') +'</p>')
}

def addBook = {
    def title = $('#title').val()
    def author = $('#author').val()
    new Book(title: title, author: author).save().then {
        appendBookToList(it)
    }
}

$(document).ready {
    drawBooks()
}

If you reload the page, now you can add books to the list, and books are saved in your database. You can check that the book is added with the url of the list of books http://localhost:8080/rest-demo/books.

You can use javascript objects in your groovy code as $ or console. println do a console.log().

Conclusion

You can use your domain classes in the client, and even better do it in groovy. You don’t have to repeat code between the server and the client, you can use domain properties and methods in the browser and the client. You reduce the code to maintain, and reduce the work of the server.

Also, you are working in groovy, and just reloading the page you see the results, you don’t have to care on class loading problems, and you will see conversion errors on grails console.

You can continue exploring grooscript grails plugin support of rest domain classes:

  • Update or delete books.

  • What happens on validation errors in the server.

  • Grails issues deleting or getting list() with parameters.

If you missing something, or need more features, add to Github