(Quick Reference)

15 Web Services - Reference Documentation

Authors: Graeme Rocher, Peter Ledbrook, Marc Palmer, Jeff Brown, Luke Daley, Burt Beckwith

Version: 2.3.0.M1

Table of Contents

15 Web Services

Web services are all about providing a web API onto your web application and are typically implemented in either REST or SOAP

15.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")
}

This maps the URI /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:

MethodAction
GETshow
PUTupdate
POSTsave
DELETEdelete

In addition, Grails provides automatic XML or JSON marshalling for you.

You can alter how HTTP methods are handled by using URL Mappings to map to HTTP methods:

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

However, unlike the 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.JSON

def 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 } } }

Issuing a request with a method other than 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>

Grails will send a hidden parameter called _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.XML

class 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 } } .. }

If there is an 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 as PUT 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>

you can read this XML packet using the same techniques described in the Data Binding section, using the params object:

def save() {
    def p = new Product(params.product)

if (p.save()) { render p as XML } else { render p.errors } }

In this example by indexing into the 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)

is that it requires no code changes to deal with a form submission that submits form data, or an XML request, or a JSON request.

If you require different responses to different clients (REST, HTML etc.) you can use content negotation

The 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).

15.2 SOAP

Grails does not feature SOAP support out-of-the-box, but there are several plugins that can help for both producing SOAP servers and calling SOAP web services.

SOAP Clients

To call SOAP web services there are generally 2 approaches taken, one is to use a tool to generate client stubs, the other is to manually construct the SOAP calls. The former can be easier to use, but the latter provides more flexibility / control.

The CXF client plugin uses the CXF framework, which includes a wsdl2java tool for generating a client. There is nothing Groovy/Grails specific here in the generated code as it simply provides a Java API which you can invoke to call SOAP web services.

See the documentation on the CXF client plugin for further information.

Alternatively, if you prefer more control over your SOAP calls the WS-Lite library is an excellent choice and features a Grails plugin. You have more control over the SOAP requests sent, and since Groovy has fantastic support for building and parsing XML it can be very productive approach.

Below is an example of a SOAP call with wslite:

withSoap(serviceURL: 'http://www.holidaywebservice.com/Holidays/US/Dates/USHolidayDates.asmx') {
    def response = send {
        body {
            GetMothersDay(xmlns: 'http://www.27seconds.com/Holidays/US/Dates/') {
                year(2011)
            }
        }
    }
    println response.GetMothersDayResponse.GetMothersDayResult.text()
}

It is not recommended that you use the GroovyWS library, it pulls in many dependencies which increases the likelihood of conflicts. The WSlite library provides a far simpler and easier to use solution.

SOAP Servers

Again, Grails does not have direct support for exposing SOAP web services, however if you wish to expose a SOAP service from your application then the CXF plugin (not to be confused with the cxf-client plugin), provides an easy way to do so.

Typically it involves taking a Grails service and adding 'expose'-style configuration, such as the below:

static expose = EndpointType.JAX_WS_WSDL
  //your path (preferred) or url to wsdl
  static wsdl = 'org/grails/cxf/test/soap/CustomerService.wsdl'

Please refer to the documentation of the plugin for more information.

15.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 } } } }