14 Web Services - Reference Documentation
Authors: Graeme Rocher, Peter Ledbrook, Marc Palmer, Jeff Brown, Luke Daley, Burt Beckwith
Version: 2.1.0
14 Web Services
Web services are all about providing a web API onto your web application and are typically implemented in either REST or SOAP14.1 REST
REST is not really a technology in itself, but more an architectural pattern. REST is very simple and just involves using plain XML or JSON as a communication medium, combined with URL patterns that are "representational" of the underlying system, and HTTP methods such as GET, PUT, POST and DELETE.Each HTTP method maps to an action type. For example GET for retrieving data, PUT for creating data, POST for updating and so on. In this sense REST fits quite well with CRUD.URL patterns
The first step to implementing REST with Grails is to provide RESTful URL mappings:static mappings = { "/product/$id?"(resource:"product") }
/product
onto a ProductController
. Each HTTP method such as GET, PUT, POST and DELETE map to unique actions within the controller as outlined by the table below:Method | Action |
---|---|
GET | show |
PUT | update |
POST | save |
DELETE | delete |
"/product/$id"(controller: "product") { action = [GET: "show", PUT: "update", DELETE: "delete", POST: "save"] }
resource
argument used previously, in this case Grails will not provide automatic XML or JSON marshalling unless you specify the parseRequest
argument:"/product/$id"(controller: "product", parseRequest: true) { action = [GET: "show", PUT: "update", DELETE: "delete", POST: "save"] }
HTTP Methods
In the previous section you saw how you can easily define URL mappings that map specific HTTP methods onto specific controller actions. Writing a REST client that then sends a specific HTTP method is then easy (example in Groovy's HTTPBuilder module):import groovyx.net.http.* import static groovyx.net.http.ContentType.JSONdef http = new HTTPBuilder("http://localhost:8080/amazon") http.request(Method.GET, JSON) { url.path = '/book/list' response.success = { resp, json -> for (book in json.books) { println book.title } } }
GET
or POST
from a regular browser is not possible without some help from Grails. When defining a form you can specify an alternative method such as DELETE
:<g:form controller="book" method="DELETE"> .. </g:form>
_method
, which will be used as the request's HTTP method. Another alternative for changing the method for non-browser clients is to use the X-HTTP-Method-Override
to specify the alternative method name.XML Marshalling - Reading
The controller can use Grails' XML marshalling support to implement the GET method:import grails.converters.XMLclass ProductController { def show() { if (params.id && Product.exists(params.id)) { def p = Product.findByName(params.id) render p as XML } else { def all = Product.list() render all as XML } } .. }
id
we search for the Product
by name and return it, otherwise we return all Products. This way if we go to /products
we get all products, otherwise if we go to /product/MacBook
we only get a MacBook.XML Marshalling - Updating
To support updates such asPUT
and POST
you can use the params object which Grails enhances with the ability to read an incoming XML packet. Given an incoming XML packet of:<?xml version="1.0" encoding="ISO-8859-1"?> <product> <name>MacBook</name> <vendor id="12"> <name>Apple</name> </vender> </product>
def save() { def p = new Product(params.product) if (p.save()) { render p as XML } else { render p.errors } }
params
object using the product
key we can automatically create and bind the XML using the Product
constructor. An interesting aspect of the line:def p = new Product(params.product)
If you require different responses to different clients (REST, HTML etc.) you can use content negotationThe
Product
object is then saved and rendered as XML, otherwise an error message is produced using Grails' validation capabilities in the form:<error> <message>The property 'title' of class 'Person' must be specified</message> </error>
REST with JAX-RS
There also is a JAX-RS Plugin which can be used to build web services based on the Java API for RESTful Web Services (JSR 311: JAX-RS).14.2 SOAP
There are several plugins that add SOAP support to Grails depending on your preferred approach. For Contract First SOAP services there is a Spring WS plugin, whilst if you want to generate a SOAP API from Grails services there are several plugins that do this including:- CXF plugin which uses the CXF SOAP stack
- Axis2 plugin which uses Axis2
- Metro plugin which uses the Metro framework (and can also be used for Contract First)
exposes
static property. This example is taken from the CXF plugin:class BookService { static expose = ['cxf'] Book[] getBooks() {
Book.list() as Book[]
}
}
http://127.0.0.1:8080/your_grails_app/services/book?wsdl
For more information on the CXF plugin refer to the documentation on the wiki.
14.3 RSS and Atom
No direct support is provided for RSS or Atom within Grails. You could construct RSS or ATOM feeds with the render method's XML capability. There is however a Feeds plugin available for Grails that provides a RSS and Atom builder using the popular ROME library. An example of its usage can be seen below:def feed() { render(feedType: "rss", feedVersion: "2.0") { title = "My test feed" link = "http://your.test.server/yourController/feed" for (article in Article.list()) { entry(article.title) { link = "http://your.test.server/article/${article.id}" article.content // return the content } } } }