- Overview (version 0.2)
- Hello world
- Scaffolding
- Overview (version 0.1)
- Prerequisites
- Getting the plugin
- Hello world
- Advanced topics
- Next steps
Important note : This page still describes version 0.1 of the plugin. Documentation for version 0.2 is work in progress.
Overview (version 0.2)
This page helps you getting started with the JSR 311 plugin for Grails. It is assumed that you have a basic understanding of Grails and the JSR 311 (JAX-RS: The Java API for RESTful Web Services). The examples in the following chapters have been tested with Grails 1.1.1. For instructions how to download and install Grails refer to the Grails reference documentation section 2.1 .
Hello world
Create a project
grails create - app hello
on the command line. This creates a new directory hello .
Install the plugin
To install the plugin from the Grails Plugin Repository , go to the created hello directory and enter
grails install - plugin jaxrs
This will download the latest released version of the plugin from the Grails Plugin Repository . For further installation options refer to the installation instructions .
Create a resource
To create a JAX-RS resource named test enter
grails create - resource test
import javax . ws . rs . GET
import javax . ws . rs . Path
import javax . ws . rs . Produces
@Path ( '/test' )
class TestResource {
@GET
@Produces ( 'text/plain' )
String getTestRepresentation () {
'Test'
}
}
Run the application
To start the application enter
grails run - app
Change the code
Using Eclipse
Using the hello project with the grails-jaxrs plugin in Eclipse requires a bit more than just importing the hello project. After import, the grails-jaxrs classes are not on the classpath of the project, therefore, you'll see compile errors for generated JAX-RS resources. The best way to resolve the compile errors is to import the grails-jaxrs plugin project as a separate project in Eclipse and reference that project from the hello project.
To checkout a released version of the grails-jaxrs project enter
svn export http : //grails-jaxrs.googlecode.com/svn/tags/jaxrs-<version> jaxrs
on the command line where <version> must be replaced by the version of the plugin you're using. This will create a local directory jaxrs , the root directory of the project. If you use a development snapshot checkout the sources from http://grails-jaxrs.googlecode.com/svn/trunk/jaxrs .
To import the project into Eclipse go to File -> Import... -> General -> Existing Projects Into Workspace and press Next . Then select the project's root directory and click Finish . You should now see a jaxrs project in the package explorer.
To add this new project as dependency to the hello project, right-click on the hello project and go to Properties -> Java Build Path -> Projects -> Add... . Select the jaxrs project from the list of projects in the workspace and press OK . The compile erros should now disappear.
Scaffolding
Create a domain class
To create a Person domain class go to the project's root directory and enter
grails create - domain - class person
class Person {
static constraints = {
}
String firstName
String lastName
}
Generate the REST API
grails generate - resources person
Use the REST API
Overview (version 0.1)
The following sections describe the (old) version 0.1 of the grails-jaxrs plugin.
This page helps you getting started with the JSR 311 plugin for Grails. It is assumed that you have a basic understanding of Grails and the JSR 311 (JAX-RS: The Java API for RESTful Web Services).
Prerequisites
- A Grails 1.1.1 (or higher) installation. For instructions how to download and install Grails refer to the Grails reference documentation section 2.1 .
Getting the plugin
Note: You can skip this section if you want to get the plugin directly from the Grails Plugin Repository .
Either download the latest plugin binary directly from directly from here or build it from its sources:
- Checkout the code from Subversion via svn checkout http://grails-jaxrs.googlecode.com/svn/trunk/jaxrs jaxrs
- Go to the created jaxrs directory.
- Enter grails test-app on the command line to run the unit and integration tests (optional)
- Enter grails package-plugin on the command line to create the plugin binary
The filename of the created plugin is grails-jaxrs-<version>.zip where <version> is the current development version. Alternatively, build the plugin from a tagged version .
Hello world
Create a project
on the command line. This creates a new directory hello .
Install the plugin
Go to the created hello directory and enter
on the comamnd line. This will download the latest released version of the plugin from the Grails Plugin Repository . If you downloaded or built the plugin as described in Getting the plugin enter
grails install-plugin /path/to/grails-jaxrs-<version>.zip
where /path/to needs to be replaced by the absolute or relative path to the grails-jaxrs plugin file.
Required libraries
In order work with JSR 311 annotations and classes the JSR 311 jar file (version 1.1) must be added to the project's lib folder.
Create a resource
In the hello project under src/groovy create a new Groovy class HelloResource.groovy :
import javax . ws . rs . GET
import javax . ws . rs . Path
import javax . ws . rs . Produces
import org . springframework . stereotype . Component
@Component
@Path ( '/test' )
class HelloResource {
@GET
@Produces ( 'text/plain' )
String greet () {
'Hello grails-jaxrs'
}
}
Setup the application context
Before the application can be started we need to add the resource to the Spring application context. We do this with a component scan . A component scan looks in the classpath for beans annotated with @Component and adds them to the application context. Here's the application context XML file (resources.xml ) that needs to be added to the grails-app/conf/spring directory of the hello project.
<beans xmlns = "http://www.springframework.org/schema/beans"
xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
xmlns:context = "http://www.springframework.org/schema/context"
xsi:schemaLocation = "
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd" >
<context:annotation-config/>
<context:component-scan base-package = "**" />
</beans>
This scans components from all packages including the default package. If you don't want to use context:component-scan add the bean <bean class="HelloResource" /> directly to the application context.
Run the application
Advanced topics
Configuration
Instead of extending the grails-app/conf/UrlMappings.groovy file directly the URL mappings for the JaxrsController are set via the org.grails.jaxrs.url.mappings configuration property. The property value is a list of URL patterns. For example, assuming that a Grails application is accessible under http://localhost:8080/hello where /hello is the context path and all JAX-RS resources are accessible via
we need to add the following entry to grails-app/conf/Config.groovy :
- org.grails.jaxrs.url.mappings=['/test', '/notes']
This ensures that only requests with a URL path matching /test/... and /notes/... are forwarded to the JaxrsController , all other requests may go to other Grails controllers. More detailed, the grails-jaxrs plugin creates the following URL mappings when it is loaded:
- "/test"(controller:"jaxrs")
- "/test/**"(controller:"jaxrs")
- "/notes"(controller:"jaxrs")
- "/notes/**"(controller:"jaxrs")
Applying filters
Grails filters can be applied to JAX-RS resources as well. For example, to add a filter for the /test/** URL pattern, create a file TestFilters.groovy under grails-app/conf with a content like
class TestFilters {
def filters = {
testUris ( uri : '/test/**' ) {
before = {
// do some preprocessing
}
after = {
// do some postprocessing
}
}
}
}
Using GORM
Usage of GORM is demonstrated on a (over-simplified) web application that keeps track of notes that have been POSTed via HTTP.
- POSTing to http://localhost:8080/hello/notes creates a new Note domain object in the database containing the actual note from the request body. The request content type is text/plain . The response content type is text/xml representing the created domain object including its identifier. The response Location header contains the URL of the created note resource.
- GETing from http://localhost:8080/hello/notes obtains a list of all created notes so far or an empty list. The response content type is text/xml .
- GETing from http://localhost:8080/hello/notes/{id } obtains a note with a certain id or an error message (along with status code 404) if a note with the given id doesn't exist.
The first step is to create the Note domain object. This can be either done via grails create-domain-class note from the command line or manually by adding a Note.groovy file with the following content to the grails-app/domain directory.
class Note {
static constraints = {
}
String text
}
The only thing a note object stores is the note text (and an id property that is available on every Grails domain object).
For creating new Note instances i.e. note resources we POST the notes text to http://localhost:8080/hello/notes . This resource is implemented with a NotesResource class
import grails . converters .*
import javax . ws . rs . Consumes
import javax . ws . rs . GET
import javax . ws . rs . Produces
import javax . ws . rs . Path
import javax . ws . rs . PathParam
import javax . ws . rs . POST
import javax . ws . rs . core . Response
import javax . ws . rs . core . UriBuilder
import org . springframework . stereotype . Component
@Component
@Path ( '/notes' )
class NotesResource {
@POST
@Consumes ( 'text/plain' )
@Produces ( 'text/xml' )
Response addNote ( String text ) {
def note = new Note ( text : text ). save ()
URI uri = UriBuilder . fromPath ( note . id as String ). build ()
Response . created ( uri ). entity ( note as XML ). build ()
}
@GET
@Produces ( 'text/xml' )
Response getNotes () {
Response . ok ( Note . findAll () as XML ). build ()
}
}
Save this class as NotesResource.groovy in the src/groovy directory. Let's take a closer look at it. The class-level @Path annotation makes this resource accessible under the /notes path i.e. the full URL is http://localhost:8080/hello/notes . POSTing to this URL will call the addNote(String) method passing the request body via the text parameter. The text parameter is used to construct a Note object which is then stored in the database. The URL for the newly created note is constructed in the second line. We use this URL to set the Location response header with Response.created(uri) . The response body contains the XML representation of the note object. To create the XML representation the XML converter of Grails is used. Here's a sample HTTP request:
POST / hello / notes / HTTP / 1.1
Content - Type : text / plain
Host : localhost : 8080
Content - Length : 27
Don 't forget to learn Scala
Here's a sample HTTP response:
HTTP / 1.1 201 Created
Content - Type : text / xml
Location : http : //localhost:8080/hello/notes/1
<? xml version = "1.0" encoding = "UTF-8" ?>
< note id = "1" >
< text > Don 't forget to learn Scala</text>
</note>
To obtain a list of all notes send a GET request to http://localhost:8080/hello/notes which will call the getNotes() method. This method again uses the Grails XML converter to create an XML representation of the notes collection, such as
HTTP / 1.1 200 OK
Content - Type : text / xml
<? xml version = "1.0" encoding = "UTF-8" ?>
< list >
< note id = "1" >
< text > Don 't forget to learn Scala</text>
</note>
<note id="2">
<text>Another important note</text>
</note>
</list>
Finally we want to obtain individual notes via http://localhost:8080/hello/notes/{id} where id is in range 1..n. This can be achieved by adding a getNote(String method to the NotesResource class:
@Component
@Path ( '/notes' )
class NotesResource {
// ... other methods omitted
@Path ( '/{id}' )
NoteResource getNote ( @PathParam ( 'id' ) String id ) {
new NoteResource ( note : Note . get ( id ))
}
}
Instead of using a fixed path we use a path template where the last path segment is the variable part of the path. It is bound to the id parameter of the getNote(String) method using a @PathParam annotation. Instead of rendering the response directly in the NotesResource class it is delegated to the NoteResource class after we've loaded the note object from the database:
import static javax . ws . rs . core . Response . Status . NOT_FOUND
import grails . converters .*
import javax . ws . rs . GET
import javax . ws . rs . Produces
import javax . ws . rs . core . Response
class NoteResource {
Note note
@GET
@Produces ( 'text/xml' )
Response getNote () {
if ( note ) {
Response . ok ( note as XML ). build ()
} else {
Response . status ( NOT_FOUND ). entity ( '<error>not found</error>' ). build ()
}
}
}
If a note object with the requested id exists an XML representation is returned, otherwise, an error message is created along with a status code 404 (NOT FOUND). For example, GETing the note http://localhost:8080/hello/notes/1 returns
HTTP / 1.1 200 OK
Content - Type : text / xml
<? xml version = "1.0" encoding = "UTF-8" ?>
< note id = "1" >
< text > Don 't forget to learn Scala</text>
</note>
Entity providers
- org.grails.jaxrs.support.MessageBodyReaderSupport<T>
- org.grails.jaxrs.support.MessageBodyWriterSupport<T>
import groovy . xml . MarkupBuilder
import java . io . OutputStreamWriter
import javax . ws . rs . Produces
import javax . ws . rs . ext . Provider
import javax . ws . rs . core . MultivaluedMap
import org . grails . jaxrs . support . MessageBodyWriterSupport
import org . grails . jaxrs . test . domain . Foo
import org . springframework . stereotype . Component
@Component
@Provider
@Produces ( 'text/xml' )
class NoteWriter extends MessageBodyWriterSupport < Note > {
void writeTo ( Note entity , MultivaluedMap httpHeaders , OutputStream entityStream ) {
def builder = new MarkupBuilder ( new OutputStreamWriter ( entityStream ))
builder . note {
id ( entity . id )
content ( entity . text )
}
// Alternative (default rendering):
// entityStream << (entity as XML)
}
}
Having such a provider in place, resource methods can return a Note object directly:
@Component
@Path ( '/notes' )
class NotesResource {
// ... other methods omitted
@Path ( '/{id}' )
Note getNote ( @PathParam ( 'id' ) String id ) {
Note . get ( id )
}
}
In this case the response looks like:
HTTP / 1.1 200 OK
Content - Type : text / xml
<? xml version = "1.0" encoding = "UTF-8" ?>
< note >
< id > 1 < /id>
<content>Don't forget to learn Scala</ content >
</ note >
Service injection
Services can be auto-injected into resource objects with the following annotations:
- by name with javax.annotation.Resource
- by type with org.springframework.beans.factory.annotation.Autowired
For example, use @Resource(name='sampleService') to inject an instance of SampleService :
@Component
@Path ( '/test' )
public class HelloResource {
@Resource ( name = 'sampleService' )
def sampleService
// ...
}
<beans xmlns = "http://www.springframework.org/schema/beans"
xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation = "
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd" >
<bean class = "HelloResource" >
<property name = "sampleService" ref = "sampleService" />
</bean>
</beans>
Next steps
The next version (0.2) of the plugin will include:
- Follow Grails conventions for resources and providers by introducing the Resource and Provider artefact types.
- Resources under grails-app/resources are auto-detected, services are injected by name (as known from controllers) and resource classes can be modified at runtime.
- Providers under grails-app/providers are auto-detected, services are injected by name (as known from controllers) and provider classes can be modified at runtime.
- No need to annotate resources and providers with @Component or @Autowired any more.
- Support both Jersey and Restlet as JAX-RS implementation. Switching between them will be possible at runtime
- Deployment of Grails JAX-RS applications to the Google App Engine (GAE). Issues with Restlet-based JAX-RS applications on GAE have been recently fixed .
- Create resource and provider classes from the command line
- Generate JAX-RS RESTful service interfaces for Grails domain classes (scaffolding).
- Documentation will be completely revised.