Posts Tagged Grails

REST: CRUD with Grails

Several weeks ago I have posted my experiences with JAX-RS. Later on, as I read and understood more about Grails, I wanted to perform a similar CRUD exercise with Grails. Grails supports REST out of the box. If somebody says that Grails rocks, you don’t have to take them at their word but try out a few examples like this (and eventually agree with them!).

Obviously, REST is lot more than CRUD, and an excellent architectural pattern in my opinion. But for this post we will restrict ourselves to the CRUD aspect.

Get started

Downloading and setting up Grails is out of scope for this post. Refer to Grails website for that. Once you have Grails setup run

grails create-app [app-name]

Replace [app-name] with what ever you want to name your app. This command should create a standard Grails project structure. We will use the embedded database (HSQLDB) and embedded servlet container (Jetty). Grails ships with them auto-configured. So use all defaults for this exercise.

Resource

The resource we will be dealing here is a simple Customer object with firstName, lastName and zipcode properties. Declare Customer.groovy in grails-app/domain.

class Customer {
  String firstName
  String lastName
  String zipcode

  static constraints = {
    firstName(blank: false)
    lastName(blank: false)
    zipcode(blank: false)
  }
}

All the properties are made mandatory, as specified in the constraints above.

URL Mappings

URL mappings in Grails is an extremely useful and powerful feature. We can set a URL mapping’s action parameter to a map that associates HTTP methods with action names. UrlMappings.groovy will go into grails-app/conf

class UrlMappings {
    def mappings = {
      "/customer" (controller: "customer") {
        action = [GET:"list", POST: "create"]
      }

      "/customer/$id" (controller: "customer") {
        action = [GET: "show", PUT:"update", DELETE:"delete"]
      }
	}
}

Here we have mapped /customer to a corresponding controller (we still have to work on the Controller, coming next), and the actions are mapped such that GET requests go to list action of the controller and POST is forwarded to save action. For a different URL pattern /customer/$id we have also provided mappings for its supported HTTP methods: GET, PUT and DELETE.

Controller

Create CustomerController.groovy in grails-app/controller, and let’s start working on CRUD operations on our resource.

Create

import grails.converters.XML

class CustomerController {
  def create = {
    def xml = request.XML
    def customer = new Customer()
    customer.firstName = xml.firstName.text()
    customer.lastName = xml.lastName.text()
    customer.zipcode = xml.zipcode.text()

    if (customer.validate()) {
      customer.save();
      response.status = 201
      render customer as XML
    } else {
      sendValidationFailedResponse(customer, 403)
    }
  }

  private def sendValidationFailedResponse(customer, status) {
    response.status = status
    render contentType: "application/xml", {
      errors {
        customer?.errors?.fieldErrors?.each {err ->
          field(err.field)
          message(g.message(error: err))
        }
      }
    }
  }
}
  • See the power of Groovy, the ease with which you can navigate XML. Populate the Customer object and validate it for constraints defined in the domain object.
  • If the validation is passed save the resource, set the status and respond back with the created resource (with id). In this context, see line 14. It can’t get any simpler than that. A domain object is transformed to XML with just that call.
  • Grails ships with two converters XML and JSON. If you want JSON response above just replace line 14 with render customer as JSON
  • rest of the code is status setting and error handling, a display of Groovy closures.

Test it
First, run your app from the command line –

grails run-app

Rest-client is an excellent REST client, I strongly recommend it for standalone testing. It has got a nice little UI and works as advertised with little fuss.

Create Customer Resource

(Click on the image to enlarge)

Read

  def list = {render Customer.list() as XML}

  def show = {
    Customer customer = Customer.get(params.id)
    if (customer) {
      render customer as XML
    } else {
      SendNotFoundResponse()
    }
  }

  private def SendNotFoundResponse() {
    response.status = 404
    render contentType: "application/xml", {
      errors {
        message("Customer not found with id: " + params.id)
      }
    }
  }
  • It doesn’t get much simpler than that. Two actions list and show display XML but act on two different URL patterns (see URL mappings). Former lists all the customers in the database and the latter provide details of a specific customer (with a given id).
  • Note that id portion is passed on using params.id field
  • Status code 404 is sent back, see SendNotFoundResponse. Response is sent back in XML.

Test it
GET is easy to test in a browser, or use Rest-client to test. See the URL, client is requesting for a resource with an Id.

Get Customer Resource

(Click on the image to enlarge)

Update
Update and Delete are very similar to the code described above. The following should be self explanatory by now.

  def update = {
    Customer customer = Customer.get(params.id)
    if (!customer) {
      SendNotFoundResponse()
    }

    def xml = request.XML
    customer.firstName = xml.firstName.text()
    customer.lastName = xml.lastName.text()
    customer.zipcode = xml.zipcode.text()

    if (customer.validate()) {
      customer.save();
      response.status = 201
      render ""
    } else {
      sendValidationFailedResponse(customer, 403)
    }
  }

Delete

  def delete = {
    Customer customer = Customer.get(params.id)
    if (!customer) {
      SendNotFoundResponse()
    }
    customer.delete();
    response.status = 204
    render ""
  }

Tags: ,

Book Review: Grails in Action

Grails in Action Cover

The Book

Title: Grails in Action

Authors: Glen Smith, Peter Ledbrook

Publisher: Manning

Review

The book is organized into four parts:

  • Introduction: The very first chapter is aptly titled as ‘Grails In a Hurry’. If you are a complete beginner to Grails you will be blown away with the productivity and the powerful feature set of Grails on display. Many concepts explained in detail in the later chapters are summarized with a simple example. Second chapter goes over Groovy basics, which is adequate.
  • Fundamentals: I think taking up a non-trivial example to explain the concepts of a framework is nice. A Twitter-like application is built during the course of this part of the book. This part explains about using GORM (Grails Object Relational Mapping Library), techniques for using Constraints for validation, power of Grails scaffolding, usage of dynamic queries, controlling application flow and the usage of services, introduction to GSPs and the discussion about views and layouts (along with AJAX stuff).
  • Building more features into your applications: How well different levels of testing (unit, integration, functional) are integrated into the framework is discussed. This part then continues with the basics of plugins and their usage. One of my favorite chapters in this book follows next, workflow with Grails Webflow. Security is discussed in some detail, but the chapter that follows really stands out (especially for a huge REST fan like me) — explains how to design and implement a RESTful API showcasing Grails support for this architectural pattern.
  • What you need to know for real work: The last part of the book explains about — messaging and scheduling, some advanced GORM concepts, how to use Spring and transactions with Grails, and about plugin development. The chapter on advanced GORM concepts is well written; folks who intend to use Grails for enterprise-level applications will certainly benefit from this chapter.

This is my first formal reading of a Grails book, but have some decent exposure to the concepts of Grails (from the available documentation, and by the presentations that I attended in the past). So for me, introductory chapters and some of the fundamentals are well-needed refreshers, but the last two parts really stand out. Some points from my notes:

  • For integration tests, Grails bootstrap the database and wires up all components just as it would for a running web app.
  • Domain class relationships (1:1, 1:M, M:N) are explained quite well from the Grails point of view — belongsTo variations, hasMany and GORM magic of automatically adding new methods to account for the defined relationships.
  • Groovy querying with dynamic finders: Dynamic finders take advantage of funky Groovy metaclass magic to intercept all method calls on a domain object; leverages Groovy’s methodMissing feature.
  • Use flash scope for passing messages to the user when a redirect is involved.
  • Extensive discussion on the Grails form taglibs, and on creating your own tags.
  • Mocking is built-in the framework for productive unit testing.
  • Webflow introduces a new scope: flow scope. Items put in flow scope live for the life of the flow. Favor flow scope over session scope — Webflow will cleanup the storage for you and give you more efficient server memory.
  • The chapter on implementing the REST architectural pattern is a must read; Grails supports the pattern out-of-the-box.
  • Grails uses OSCache as its default cache library (for Hibernate’s second-level cache). The reason suggested was that it plays well with Grails developer restarts, something I would like to understand further in reference to Ehcache. But the authors actually used Ehcache in the book suggesting that it is a better library (I agree!).
  • So easy to declare caching at the domain level:
    static mapping = {
        cache: “read-write”
    }
  • Discussion on integrating with legacy databases is interesting, but would like to see some case studies to understand the real pain involved.
  • Transactional services are implemented using Spring’s AOP mechanism (Spring’s TransactionProxyFactoryBean).
  • Integration tests run inside a transaction by default, which is then rolled back after each test finishes. This ensures that data changes don’t affect other tests, but it means you can’t check whether transactions are rolled back or not. If you want to test transactional behavior then you need to add a static transactional property to your test.

Conclusion

The book is very well organized and the topics chosen are well thought of. An easy conversational tone is used through out the book. In my opinion, this book succeeds in building a sustained interest about the framework. It is also an excellent reference book on the topic. Strongly recommend the book for all Grails enthusiasts.

Tags: ,