|
GettingStarted
A quick guide to getting started with the JSR 311 plugin for Grails.
Featured OverviewThis page helps you getting started with the JSR 311 plugin for Grails. It is assumed that you have a basic understanding of Grails and JSR 311 (JAX-RS: The Java API for RESTful Web Services). The examples in the following chapters have been tested to work with Grails 1.3.1 but should also work with Grails 1.2.x. For instructions how to download and install Grails refer to the Grails reference documentation section 2.1. The Using Eclipse section on this page explains how to setup the examples in Eclipse. Hello worldCreate a projectTo use the plugin we create a new Grails project. Change the working directory to a location where you want to create a new Grails project and enter grails create-app hello on the command line. This creates a new directory hello. Install the pluginTo 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, such as installing a development snapshot, refer to the installation instructions. Create a resourceTo create a JAX-RS resource named test enter grails create-resource test This will create a TestResource.groovy file under grails-app/resources and a TestResourceTests.groovy file under test/unit. The TestResourceTests.groovy file is a unit test template. The TestResource.groovy file is the generated JAX-RS resource. Both files are in the hello package. package hello
import javax.ws.rs.GET
import javax.ws.rs.Path
import javax.ws.rs.Produces
@Path('/api/test')
class TestResource {
@GET
@Produces('text/plain')
String getTestRepresentation() {
'Test'
}
}It defines a single method that responds to HTTP GET operations. The HTTP response contains the return value of this method, Test in this example. The content type of the response (Content-Type header) is text/plain. The created resource is ready to use as shown in the next section. Creating resources via the command line is only one option. An alternative is to create resource files by hand. Any *Resource.groovy file created under grails-app/resources is assumed to be a JAX-RS resource and auto-detected by the grails-jaxrs plugin. These resources are checked for the presence of JAX-RS annotations as defined by JAX-RS 1.1 specification, section 3.1. Resources that aren't properly annotated are ignored by the plugin. Run the applicationTo start the application enter grails run-app on the comamnd line. Then open a browser window and go to http://localhost:8080/hello/api/test. The browser should now display "Test". Change the codeThe grails-jaxrs plugin also support code changes at runtime i.e. without restarting the server. To demonstrate that we let add a name parameter to the getTestRepresentation method and bind it to a name query parameter using the JAX-RS @QueryParam annotation. The HTTP response entity will vary depending on the name query parameter. Here's the modified source code. package hello
import javax.ws.rs.GET
import javax.ws.rs.Path
import javax.ws.rs.Produces
import javax.ws.rs.QueryParam
@Path('/api/test')
class TestResource {
@GET
@Produces('text/plain')
String getTestRepresentation(@QueryParam('name') String name) {
"Hello ${name ? name : 'unknown'}"
}
}When you save the changes the plugin re-initializes the JAX-RS runtime. Go to http://localhost:8080/hello/api/test?name=Martin and you should see Hello Martin in the browser window. If you additionally want to factor out the greeting logic into a Grails service, refer to the service injection section for instructions. Generate WADLAvailable in version 0.4 or higher. A WADL document for resources managed by the plugin can be generated by sending a GET request to http://localhost:8080/hello/application.wadl. The result should look like <application xmlns="http://research.sun.com/wadl/2006/10">
<doc xmlns:jersey="http://jersey.dev.java.net/" jersey:generatedBy="Jersey: 1.1.4.1 11/24/2009 01:30 AM"/>
<resources base="http://localhost:8080/hello/">
<resource path="/api/test">
<method name="GET" id="getTestRepresentation">
<request>
<param xmlns:xs="http://www.w3.org/2001/XMLSchema" type="xs:string" style="query" name="name"/>
</request>
<response>
<representation mediaType="text/plain"/>
</response>
</method>
</resource>
</resources>
</application>Generating WADL documents only works when the plugin is configured to use Jersey as JAX-RS implementation. ScaffoldingThe grails-jaxrs plugin also supports scaffolding. It allows you to generate a RESTful service interface for one or more domain classes based on JAX-RS resource classes. Supported representation formats are XML and JSON. The following sections walk through a simple example. Please note that the scaffolding feature of the plugin is still early-access. Create a domain classTo create a Person domain class go to the project's root directory and enter grails create-domain-class person Open the generated Person.groovy file (under grails-app/domain) and add two properties, firstName and lastName. package hello
class Person {
static constraints = {
}
String firstName
String lastName
}Generate the REST APITo generate JAX-RS resources that implement the RESTful service interface for that domain class enter grails generate-resources hello.Person This will generate two resource classes, PersonCollectionResource.groovy and PersonResource.groovy (in the hello package) that support HTTP POST, GET, PUT and DELETE operations for creating, reading, updating and deleting Person objects, respectively. PersonCollectionResource.groovy is related to Person lists, PersonResource.groovy is related to individual Person instances. Let's take a look at how to use the generated RESTful service interface. Use the REST APIStart the hello application with grails run-app New person objects can be created by POSTing to http://localhost:8080/hello/api/person. The following request POSTs an XML representation of a person object. POST /hello/api/person HTTP/1.1 Content-Type: application/xml Accept: application/xml Host: localhost:8080 Content-Length: 82 <person> <firstName>Sam</firstName> <lastName>Hill</lastName> </person> The Content-Type header must be set either to application/xml. After sending the request, the server creates a new person object in the database and returns an XML representation of it. 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> The client explicitly requested an XML representation via the Accept request header. Note that the returned representation differs from the submitted representation by an id attribute in the <person> element. This id is also contained in the Location response header, the URL of the created resource. The response code is 201 (CREATED). Let's create another person object using a JSON representation. Here's the request 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"}The response also contains a JSON representation of the created person (see Accept request header). The id of the created person object is 2. 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"}Content negotiation via Content-Type and Accept headers works for other HTTP methods as well. To GET a list of created persons, open a browser (Firefox in our example) and enter the URL http://localhost:8080/hello/api/person. This returns an XML representation of the list of persons stored in the database.
An XML representation is returned because Firefox sets an Accept=text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 request header. To get the representation of a single person, specify the id in the URL. For example, to get the person with id 1 use http://localhost:8080/hello/api/person/1
If you try to get a person that doesn't exist, an error message (with a status code 404) is returned.
In the next step we update the first name of person 1 by PUTting a new representation to http://localhost:8080/hello/api/person/1. PUT /hello/api/person/1 HTTP/1.1 Content-Type: application/xml Accept: application/xml Host: localhost:8080 Content-Length: 85 <person> <firstName>Samuel</firstName> <lastName>Hill</lastName> </person> The response is a new representation of the updated person. HTTP/1.1 200 OK Content-Type: application/xml Transfer-Encoding: chunked Server: Jetty(6.1.14) <?xml version="1.0" encoding="UTF-8"?> <person id="1"> <firstName>Samuel</firstName> <lastName>Hill</lastName> </person> GETting the person list again shows the update of person 1.
Finally, we delete person 1 by sending a DELETE request to http://localhost:8080/hello/api/person/1. DELETE /hello/api/person/1 HTTP/1.1 Accept: application/xml Host: localhost:8080 GETting the person lists again shows that person 1 has actually been deleted.
The using GORM section of the advanced features page walks through the source code of the generated JAX-RS resources. Using EclipsePrerequisites: Eclipse 3.5.x or higher and an installation of the SpringSource Tool Suite (STS). 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 git clone git://github.com/krasserm/grails-jaxrs.git on the command line. This will create a local repository grails-jaxrs, which is the root directory of the project. Then switch the repository to a tagged version or leave the master branch if you want to use the latest development version. 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. Next steps
|
Hi , I'm having a problem to start my application in Eclipse. After configuring everything like in the user guide,an exception is being thrown:
Exception sending context initialized event to listener instance of class org.grails.jaxrs.web.JaxrsListener? com.sun.jersey.api.container.ContainerException?: The ResourceConfig? instance does not contain any root resource classes.
What could this be? Thanks
Jersey complains that there's no JAXRS resource class defined. Just create one as described in this guide and the exception should disappear. Does that help?
Even when I have a resource created, I'm receiving this same error.
Then I need to know more about your app e.g. what Grails version you're using, grails-jaxrs version, STS version etc.
Does it work when running from the command line with 'grails run-app'? Do you have the resource classes in directory grails-app/resources? With STS, did you run Grails -> Refresh Dependencies from the context menu? Any other plugins installed?
Just tried it with Grails 1.3.1, grails-jaxrs 0.4, STS 2.3 and everything works as expected. Can you package and send me your app if the above advices don't help?
I'm having similar issues with the plugin not finding root resource classes. Strangely, everything works perfectly in another environment that is ostensibly identical, but trying to transfer the project to another computer just doesn't work.
For some reason application.resourceClasses in JaxrsGrailsPlugin?.groovy is empty. I've no real insight on how Grails plugins work so it's hard to say what is causing this... I've tried Grails 1.3.4 - 1.3.5, STS 2.3 - 2.5 and the plugin is the default 0.4 available from the Grails repo. Other plugins include code-coverage, hibernate, rest, spock, spring-security-core and tomcat.
@esa In order to help you, I need more information about your project. Can you share your project (preferrably on github) so that I can try to reproduce it?
Thanks for the help, but can't really share the project (it's quite large and contains some proprietary client stuff). I'll see if I can debug the issue some more, maybe learn something while I'm at it...
Well, not sure how, but everything now seems to work just fine. I traced the problem back to JaxrsClasses?.isJaxrsResource (which returned false even for resource classes) and added some debugging code. Surprisingly, the app started to work. I reverted the changes to JaxrsClasses?.groovy, and still the app worked. So it seems just touching the file did the trick.
I also tried to break things again by deleting and re-checking out the project, and by deleting ~/.grails/1.3.5/projects/myproject/plugins/jaxrs-0.4, but still everything works. Will have to see if the problem ever occurs again, but for now I'm happy, although confused.
I had a working app but encountered the same issue after a 'grails clean'. Another 'grails clean' fixed the issue.
If you receive an error after installing the plugin try using the restlet implementation by changing the config file as described here: https://code.google.com/p/grails-jaxrs/wiki/AdvancedFeatures#JAX-RS_implementation
Hi while POSTing the request am getting the error like this... HTTP Status 415 -The server refused this request because the request entity is in a format not supported by the requested resource for the requested method ().
I just posted exactly like this... POST /hello/api/person HTTP/1.1 Content-Type: application/xml Accept: application/xml Host: localhost:8080 Content-Length: 82
<person>
</person>Can any one please help me to resolve the issue...
@sathyak1989, try