Saturday, December 12, 2009

New features in grails-jaxrs 0.3

In this blog post I present some new features of the recently released grails-jaxrs 0.3 plugin. A complete list of new features is available in the release notes. A feature overview and links to the complete documentation is on the plugin home page.

grails-jaxrs is a Grails plugin that supports the development of RESTful web services based on the Java API for RESTful Web Services (JSR 311: JAX-RS). It is targeted at developers who want to structure the web service layer of an application in a JSR 311 compatible way but still want to continue to use Grails' powerful features such as GORM, automated XML and JSON marshalling, Grails services, Grails filters and so on. This plugin is an alternative to Grails' built-in mechanism for implementing RESTful web services.

The following example shows how to do content negotiation for Grails domain objects. Grails domain classes like

class Person {
String firstName
String lastName
}

can now be used in JAX-RS resource methods directly (e.g. Person parameter in the create method):

import static javax.ws.rs.core.UriBuilder.fromPath

import javax.ws.rs.Consumes
import javax.ws.rs.Path
import javax.ws.rs.Produces
import javax.ws.rs.POST
import javax.ws.rs.core.Response

@Path('/api/person')
@Consumes(['application/xml','application/json'])
@Produces(['application/xml','application/json'])
class PersonCollectionResource {

@POST
Response create(Person person) {
person.save() // use GORM
URI uri = fromPath(person.id as String).build()
Response.created(uri).entity(person).build()
}

// ...

}

Content negotiation and conversion between domain objects and their XML or JSON representations is done by domain object providers. There's no need any more for application code to deal with representation formats directly.

The PersonCollectionResource.create method handles POST requests for creating new Person objects in the database. The method uses GORM to persist the domain object. Clients can send either XML or JSON representations for POSTing person data (see Content-Type header):

POST /hello/api/person HTTP/1.1
Content-Type: application/xml
Accept: application/xml
Host: localhost:8080
Content-Length: 78

<person>
<firstname>Sam</firstname>
<lastname>Hill</lastname>
</person>

or

POST /hello/api/person HTTP/1.1
Content-Type: application/json
Accept: application/json
Host: localhost:8080
Content-Length: 58

{"class":"Person","firstName":"Fabien","lastName":"Barel"}

In either case, the plugin will convert it to a Person object, as required by the person parameter. For creating a response the method uses the JAX-RS API. It first creates a URI for the response Location header and uses the Response builder to set the status code to 201 (created) and the response entity. Note that the method itself doesn't create an XML or JSON representation of the response domain object. This is again done by a domain object provider which uses the Accept request header to determine the response representation format. The responses to the above POST requests are:

HTTP/1.1 201 Created
Content-Type: application/xml
Location: http://localhost:8080/hello/api/person/1
Transfer-Encoding: chunked
Server: Jetty(6.1.14)

<?xml version="1.0" encoding="UTF-8"?>
<person id="1">
<firstname>Sam</firstname>
<lastname>Hill</lastname>
</person>

and

HTTP/1.1 201 Created
Content-Type: application/json
Location: http://localhost:8080/hello/api/person/2
Transfer-Encoding: chunked
Server: Jetty(6.1.14)

{"class":"Person","id":"2","firstName":"Fabien","lastName":"Barel"}

The PersonCollectionResource.create method is even more verbose than necessary. It could equally be written as

import static org.grails.jaxrs.response.Responses.*

@Path('/api/person')
@Consumes(['application/xml','application/json'])
@Produces(['application/xml','application/json'])
class PersonCollectionResource {

@POST
Response create(Person person) {
created person.save()
}

// ...

}

using helper methods (a mini-DSL) from org.grails.jaxrs.response.Responses. That's exactly the code that is generated when using scaffolding for the Person domain class i.e.

grails generate-resources person

With the grails-jaxrs scaffolding feature, one can generate RESTful service interface for domain objects supporting the HTTP methods POST, GET, PUT and DELETE. A scaffolding example is given in the Scaffolding section of the grails-jaxrs documentation, a walk through the generated code is in the Using GORM section.

By default, grails-jaxrs uses Grail's XML and JSON converters for converting between domain objects and their XML or JSON representations. Applications can easily customize this conversion logic as explained in the Custom entity providers section.

Besides usage of GORM, grails-jaxrs also supports auto-injection of Grails services into JAX-RS resource and provider classes or usage of Grails filters, to mention a few. With version 0.3 the included JAX-RS implementations have been upgraded to their latest versions: Jersey 1.1.4.1 and Restlet 2.0-M6.