CHAPTER 15
Web Services

The idea of web services has been a dream of the IT industry for what seems like forever. The ability to compose applications from multiple, disparate services available over the Web was initially put forward by the SOAP standard. SOAP defined a protocol for exchanging XML messages over a network in a language-neutral way. Although still widely used, SOAP has never really fulfilled its potential, and a simpler model has emerged called Representational State Transfer 11 (REST). REST is a simple architectural style that utilizes the nature of the Web and its HTTP protocol to enable web services communication.

Unlike SOAP, REST is not really a standard and in fact doesn't even specify a requirement for the type of the payloads sent between client and server. For example, some users of REST services choose to use JavaScript Object Notation (JSON) or a custom format instead of XML in their REST APIs. Nevertheless, the idea behind REST is to use simple messages for communication and to take advantage of HTTP methods like GET, PUT, POST, and DELETE to model the different verbs found in Create/Read/Update/Delete (CRUD) applications.

While REST embraces the very nature of the Web, SOAP, on the other hand, tries to stay protocol neutral and has no dependency on HTTP. SOAP is designed to be used in conjunction with a set of tools or libraries that generate the client stub and server skeleton code to facilitate communication either ahead of time or at runtime. Both have their respective advantages and disadvantages. SOAP is very comprehensive, defining web service standards for everything from security to metadata. However, it is also extremely complex in comparison to REST, which targets simplicity.

As you may recall, the main aim of Grails is to embrace simplicity, and in this sense, REST is a far better fit for Grails than SOAP—so much so that Grails provides REST support out of the box. However, several organizations are still committed to the SOAP standard, and in this chapter, you will see how to add both SOAP and the REST APIs to a Grails application.

In addition, we'll be looking at the related syndication technologies Really Simple Syndication (RSS) and Atom. 12 Although not strictly web services related, RSS and Atom are similar in that they provide a way to publish information over the Web using a standard XML format. In fact, Google's GData web service APIs have standardized on an Atom-based format for XML payloads.

REST

As already mentioned, REST defines an architectural style for defining web services. Each HTTP method, such as POST and GET, signifies a verb or action that can be executed on a noun. Nouns are represented by URL patterns often referred to as resources in REST. Data is typically exchanged using Plain Old XML (POX), an acronym established to differentiate web services that use regular XML for data exchange from specialized versions of XML, such as the one found in SOAP. However, many public REST web services also use JSON as the data transfer format. Ajax clients in particular get massive benefit from JSON web services because client-side JavaScript found in the browser has fewer problems parsing JSON data.

So, how does REST fit into a Grails-based architecture? If you think about it, the HTTP "verbs" map nicely onto controller actions. Each controller is typically associated with a domain class that represents the noun. All you need is a good way to get Grails to execute different actions based on the HTTP verb. One way to do this is to define a default index action that uses a switch statement, as shown in Listing 15-1.

Listing 15-1. Manually Implementing a RESTful Controller

class AlbumController {
    def index = {
        switch(request.method) {
            case "GET":
                return show()
                break
            case "PUT":
                return save()
                break
            ...
        }
    }
}

The approach shown in Listing 15-1 is a bit repetitive and ugly. Luckily, there is a better way using URL mappings.

RESTful URL Mappings

For any given URL mapping, you can tell Grails to execute different actions based on the incoming request method. Listing 15-2 shows the syntax to achieve this.

Listing 15-2. Mapping onto Different Actions Based on the HTTP Method

static mappings = {
    "/album/$id?"(controller:"album") {
        action = [GET:'show', PUT:'save', POST:'update', DELETE:'delete']
    }
}

By assigning a map literal, where the keys are the HTTP method names, to the action parameter in the body of the closure passed to the URL mapping, you can tell Grails to map different HTTP methods to different actions. Now if you open up a browser and go the URI /album, Grails will detect the HTTP GET request and map to the show action of the AlbumController. If you then created an HTML form that used the HTTP POST method to submit, the update action would be used instead.

Of course, the example in Listing 15-2 is still using the database identifier to identify albums. One of the defining aspects of REST is to use the semantics of the Web when designing your URI schemes. If you consider for a moment that in the gTunes application you have artists, albums, and songs, it would be great if REST clients could navigate the gTunes store simply by using the URI. Take a look at the URL mapping in Listing 15-3, which presents an example of using URL mappings that better represents the nouns within the gTunes application.

Listing 15-3. RESTful URL Example

static mappings = {
    "/music/$artist/$album?/$song?"(controller:"store") {
        action = [GET:'show', PUT:'save', POST:'update', DELETE:'delete']
    }
}

The example in Listing 15-3 shows a URL mapping that allows semantic navigation of the gTunes store. For example, if you wanted to retrieve information about the Artist Beck, you could go to /music/Beck. Alternatively, if you're interested in a particular Album by Beck, you could go to /music/Beck/Odelay, and so on.

The disadvantage of the approach in Listing 15-3 is that you are essentially mapping the entire pattern onto a single controller—the StoreController. This places a load of burden on the StoreController because it needs to know about artists, albums, and songs. Really, it would be desirable to map differently depending on which URL tokens have been specified. To achieve this, you could use a closure to define the name of the controller to map to, as shown in Listing 15-4.

Listing 15-4. Dynamically Mapping to a Controller

"/music/$artistName/$albumTitle?/$songTitle?"{
    controller = {
        if(params.albumTitle && params.songTitle) return 'song'
        else if(params.albumTitle) return 'album'
        else return 'artist'
    }
    action = [GET:'show', PUT:'save', POST:'update', DELETE:'delete']
}

The code in Listing 15-4 shows a technique where you can use a closure to change the controller (or action or view) to map to using runtime characteristics such as request parameters. In this case, if you have enough information to retrieve a Song (such as the artist name, album title, and song title), then the SongController is mapped to; otherwise, if only the artist name and album title are specified, the AlbumController is mapped to, and so on.

One of the powerful characteristics of REST that you may have already noticed is that it behaves very much like a regular web application. The same AlbumController can be used to deal with both incoming REST requests and regular web requests. Of course, you need to be able to know whether to send back an XML response, in the case of a web service, or a plain HTML page. In the next section, you'll see how to achieve this with content negotiation.

Content Negotiation

Grails controllers have the ability to deal with different incoming request content types automatically through a mechanism known as content negotiation. Although not specific to web services (you could equally use this technique with Ajax or to support different browser types), content negotiation is often used in conjunction with RESTful web services. The idea behind content negotiation is to let a controller automatically detect and handle the content type requested by the client. A few mechanisms can be used to achieve this:

  • Using the ACCEPT or CONTENT_TYPE HTTP headers, Grails can detect which is the preferred content type requested by the client. The mechanics of this will be explained in the next section.s
  • Using a format request parameter, clients can request a specific content type.
  • And finally, content negotiation can also be triggered using the file extension in the URI, as in /album/list.xml.

We'll cover each of these mechanisms in the next few sections, starting with content negotiation via the HTTP ACCEPT header.

Content Negotiation with the ACCEPT Header

Every browser that conforms to the HTTP standards is required to send an ACCEPT header. The ACCEPT header contains information about the various MIME types13 the client is able to accept. For example, a mobile client that supports only responses in the Wireless Application Protocol,14 often found in mobile phones, would send an ACCEPT header something like this:

application/vnd.wap.wmlscriptc, text/vnd.wap.wml

Tip For a detailed overview of the ACCEPT header, take a look at the specification provided by the W3C at http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html.


The list of supported MIME types is defined as a comma-separated list, where the most appropriate MIME type is first in the list. Modern browsers such as Firefox 3 typically send an ACCEPT header like the following:

text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8

Notice the q parameter after application/xml? The ACCEPT header can specify a "quality" rating for each MIME type. The default quality is 1.0, and the higher the quality, the more appropriate the MIME type. As you can see from the Firefox 3 header, text/html has the highest priority. For Grails to know which MIME types it should handle, you may need to provide additional configuration in grails-app/conf/Config.groovy using the grails.mime.types setting. You'll notice that Grails provides a default set of configured types for each project, an example of which is shown in Listing 15-5.

Listing 15-5. Configuring Additional MIME Types

grails.mime.types = [ html: ['text/html','application/xhtml+xml'],
                                          xml: ['text/xml', 'application/xml'],
                                          js: 'text/javascript',
                                          ...
                                       ]

To tell Grails to handle other types beyond the preconfigured ones, you need to add a new entry into the grails.mime.types map where the key is the file extension of the format typically used and the value is the MIME type found in the ACCEPT header. For example, to add support for WAP, where Wireless Markup Language (WML) files are typically served, you can add the following configuration:

grails.mime.types = [ html: ['text/html','application/xhtml+xml'],
                                          wml: ['text/vnd.wap.wml'],
                                          ...
                                       ]

Of course, if you don't need to support any niche formats such as WML, you can skip this configuration. For the purposes of REST web services, Grails is already preconfigured to be able to handle XML requests. So, how exactly do you deal with a request that needs to send back multiple formats? If you simply want to know the format of an incoming request in order to use branching logic, you can use the format property of the request object:

assert request.format == 'xml'

However, Grails provides a more elegant way to deal with different format types using the withFormat method of controllers. Using withFormat, you can tell a controller to handle XML, HTML, and even WML requests differently. For example, take a look at the code in Listing 15-6.

Listing 15-6. Using the withFormat Method

1 import grails.converters.*
2 class ArtistController {
3    def show = {
4    def artist = params.artistName ? Artist.findByName(params.artistName) :
5                                                          Artist.get(params.id)
6
7    if(artist) {
8        withFormat {
9              html artist:artist, albums:artist?.albums
10            xml { render artist as XML }
11        }
12    }
13    else {
14        response.sendError 404
15    }
16  }
17  ...
18 }

The code in Listing 15-6 shows how to handle a request when the URL mapping in Listing 15-4 ends up mapping to the ArtistController. Quite a few new concepts have been introduced in such a small snippet of code, so to understand it fully, let's step through it line by line starting with line 1:

1 import grails.converters.*

Here the grails.converters package is imported, which provides features to enable the marshaling of Java objects into XML or JSON. You'll see the significance of this later; for the moment, take a look at the first change to the code on line 7:

8        withFormat {

Using the withFormat method, which takes a block, you can send different responses for different request formats. Each nested method within the passed closure matches the name of a format; for example, the html method on line 9 handles regular browser requests:

9            html artist:artist, album:album

Notice that you can pass a model to the view to be rendered. In this case, the withFormat method will pass control to a view called grails-app/views/artist/show.gsp, which doesn't exist just yet. Finally, on line 10, you can see the code that deals with an XML response:

10            xml { render artist as XML }

In this example, you can see the first usage of the grails.converters package. The expression render artist as XML uses the imported grails.converters.XML converter to automatically marshal the Artist instance into the XML format. That's pretty simple, but how does a client go about communicating with this XML API? Well, think about how you interact with the application using your browser. For example, load the gTunes application, go to the store, and navigate to one of the existing artists using the REST URI conventions you established in Listing 15-4 such as /music/Kings of Leon.

Unsurprisingly, you get a 404 error since the grails-app/views/artist/show.gsp view does not exist. You can create it quickly, as shown in Listing 15-7.

Listing 15-7. The Artist show.gsp View

<g:applyLayout name="storeLayout">
    <g:render template="artist" model="[artist:artist]">
</g:render> </g:applyLayout>

As you can see, the show.gsp view is pretty trivial since you already created a template called _artist.gsp that does the hard work. Now if you refresh, you should get the view rendered appropriately, as shown in Figure 15-1.

image

Figure 15-1. The grails-app/views/artist/show.gsp view rendered

Take note of the URL in the address bar. If you have set up the URL mappings as shown in Listing 15-2, you should have a URL something like http://localhost:8080/gTunes/music/KingsofLeon. Now load the Grails console by typing the command grails console into a separate command window from the root of the gTunes project. With that done, try the script in Listing 15-8.

Listing 15-8. Communicating with a REST API

url = new URL("http://localhost:8080/gTunes/music/Kings%20Of%20Leon")

conn = url.openConnection()
conn.addRequestProperty("accept","application/xml")

artist = new XmlSlurper().parse(conn.content)

println "Artist Name = ${artist.name}"

Notice how in Listing 15-8 the addRequestProperty method of the URLConnection object is used to set the ACCEPT header to application/xml. The result is that instead of the HTML response you got from the browser, you get an XML one. If you want to see the XML sent back from the server, try replacing the XmlSlurper parsing code with the following line:

println conn.content.text

The response sent back by the withFormat method and its usage of the expression render artist as XML will result in XML that can be parsed with a parser like Groovy's XmlSlurper, an example of which is shown in Listing 15-9.

Listing 15-9. Grails' Automatic XML Marshaling Capabilities


<?xml version="1.0" encoding="UTF-8"?>
<artist id="4">
  <albums>
    <album id="4"/>
  </albums>
  <dateCreated>2008-08-04 21:05:08.0</dateCreated>
  <lastUpdated>2008-08-04 21:05:08.0</lastUpdated>
  <name>Kings of Leon</name>
</artist>

Grails has used the ACCEPT header in combination with the withFormat method to establish what kind of response the client is anticipating. Since the topic of marshaling to XML is a pretty important one when it comes to REST, we'll be looking at it in more detail later in the chapter. First, however, let's look at one gotcha related to ACCEPT header content negotiation.

The ACCEPT Header and Older Browsers

Depending on the clients you expect to serve, the ACCEPT header might not be so reliable. There is a nasty catch when using the ACCEPT header in that older browsers, including Internet Explorer 6 and older, simply specify */* within the ACCEPT header, meaning they accept any format.

So, how does Grails deal with an ACCEPT header of */*? Well, if you look at the withFormat definition in Listing 15-6, you'll notice that the html method is called first, followed by the xml method. If the ACCEPT header contains */*, then Grails will invoke the first method it finds within the withFormat method, which in this case is the html method. The result is that, even on older browsers, HTML will be served by default.

If this is not the desired behavior, you can also specify a method within the withFormat block to deal with an ACCEPT header containing */*. You may have noticed that the grails.mime.types setting of the grails-app/conf/Config.groovy file matches a MIME type of */* to a format called all:

grails.mime.types = [ ...,
                                     all: '*/*']

What this means is that within the withFormat block, you can define a method to handle the all format type, as shown in the example in Listing 15-10.

Listing 15-10. Dealing with the all Format

withFormat {
    html artist:artist, albums:artist?.albums
    all artist:artist, albums:artist?.albums
    xml { render artist as XML }
}

In this case, Listing 15-10 is not doing anything differently, but you could have your own custom logic to deal with all if required. If this is too dreadful to contemplate and you prefer not to use the ACCEPT header, then consider the techniques in the following sections.

Content Negotiation with the CONTENT_TYPE Header

An alternative to using the ACCEPT header is to use the HTTP CONTENT_TYPE header, which is designed to specify the incoming content type of the request. To try a client that uses the CONTENT_TYPE header, open the Grails console again, and run the script in Listing 15-11.

Listing 15-11. Communicating with a REST API Using the CONTENT_TYPE Header

url = new URL("http://localhost:8080/gTunes/music/Kings%20Of%20Leon")

conn = url.openConnection()
conn.addRequestProperty("content-type","application/xml")

artist = new XmlSlurper().parse(conn.content)
println "Artist Name = ${artist.name}"

The code is identical to Listing 15-8 except that the CONTENT-TYPE header is passed to the addRequestProperty method. The CONTENT_TYPE header always takes precedence over the ACCEPT header if both are specified. Another advantage of using the CONTENT_TYPE header is that the API support for manipulating the content type is a little simpler for Ajax clients. For example, you could use some JavaScript and the Prototype library in Listing 15-12 to call the web service and manipulate the incoming XML.

Listing 15-12. Calling REST Web Services from JavaScript

new Ajax.Request("http://localhost:8080/gTunes/music/Kings%20Of%20Leon",
                 {    contentType:"text/xml",
                    onComplete:function(response) {
                         var xml = response.responseXML;
                         var root = xml.documentElement;
                         var elements = root.getElementsByTagName("name")
                         alert("Artist name = " + elements[0].firstChild.data);
                     }
                 })

Note The JavaScript in Listing 15-12 works only because it is being run from the same host and port as the server application. One of the limitations of JavaScript is that cross-domain Ajax is forbidden for security reasons. However, there are ways around these limitations by using subdomain tricks and also by allowing users of the web service to include JavaScript served by your server. There is even an initiative to create a standard for cross-domain communication (see http://ajaxian.com/archives/the-fight-for-cross-domain-xmlhttprequest). However, the topic is broad and beyond the scope of this book.


As you can see in Listing 15-12, by specifying the contentType option passed to Prototype's Ajax.Request object, you can tell Prototype to send a different CONTENT_TYPE header in the request. The onComplete event handler can then take the resulting XML and manipulate it via the JavaScript Document Object Model (DOM). So, that's it for the HTTP headers involved in content negotiation. In the next couple of sections, we'll cover some alternative ways to handle different formats.

Content Negotiation Using File Extensions

One of the easiest ways to specify that the client needs a particular format is to use the file extension in the URI. As an example, open the Grails console again, and try the script in Listing 15-13.

Listing 15-13. Using the File Extension for Content Negotiation

url = new URL("http://localhost:8080/gTunes/music/Kings%20Of%20Leon.xml")

conn = url.openConnection()
artist = new XmlSlurper().parse(conn.content)

println "Artist Name = ${artist.name}"

Notice that, unlike the script in Listing 15-11, the definitions of the CONTENT_TYPE and ACCEPT headers have been removed from this example. Instead, the extension .xml is specified in the URI, from which Grails automatically recognizes that XML is being requested and sends back an XML response.

If you remove the XML MIME type definition from the grails.mime.types setting in grails-app/conf/Config.groovy, Grails will no longer deal with the .xml file extension. If you prefer to not use this feature at all, you can disable it completely by setting grails.mime. file.extensions in Config.groovy to false:

grails.mime.file.extensions=false

Content Negotiation with a Request Parameter

The final form of content negotiation is to use the format request parameter. For example, the code in Listing 15-13 can be adapted to use the format request parameter simply by changing the first line:

url = new URL("http://localhost:8080/gTunes/music/Kings%20Of%20Leon?format=xml")

Notice how instead of using the file extension .xml, the format parameter is passed with a value of xml. As an alternative to specifying the format parameter in the URL itself, you could provide it via a URL mapping. For example, consider the code added to the grails-app/conf/ UrlMappings.groovy file in Listing 15-14.

Listing 15-14. Proving the format Parameter in a URL Mapping

"/music/$artist"(controller:"artist") {
    action = "show"
    format = "xml"
}

Highlighted in bold in Listing 15-14 is the format parameter. As you learned in Chapter 6, you can provide parameters directly in the URL mapping!

And with that, we have completed the tour of the different ways to trigger content negotiation. However, a typical scenario in content negotiation is to have multiple different views for different format types. In the next section, you'll find out how to achieve this.

Content Negotiation and the View

Consider for a moment the usage of the withFormat method in Listing 15-6. You'll note that currently the code is handling two different format types: xml and html. In the case of xml, the code renders some XML directly to the response, and in the case of html, it is utilizing a view. However, what if you changed the code to look like the snippet in Listing 15-15?

Listing 15-15. Multiple View Delegates Within withFormat

withFormat {
    html artist:artist, albums:artist?.albums
    wml artist:artist, albums:artist?.albums
    xml { render artist as XML }
}

Notice how in Listing 15-15 there is the addition of a new withFormat handler that deals with wml. It too delegates to a view, so now you have two different format types delegating to the same view! That's putting a lot of responsibility on the view to know exactly which format type it's dealing with. Imagine the hideous if/else branching you would have to do to serve both HTML and WML in the same view! Luckily, there is another way. If you include the file extension at the end of the view name but before the .gsp extension, Grails will choose the view that is most specific.

For example, in the case of Listing 15-15, if you had a view called grails-app/views/artist/show.wml.gsp, then that view would be responsible for serving WML pages, and if you had a view called grails-app/views/artist/show.html.gsp, that view would deal with standard HTML. Of course, if a view can't be found to match a particular format, then Grails falls back on the usual conventions by using the regular show.gsp view. Nevertheless, as you can see, Grails makes it easy to serve different views for different format types using the power of Convention over Configuration.

So, in the earlier "Content Negotiation with the ACCEPT Header" section, we touched on XML marshaling with the grails.converters package. In the next few sections, you'll get a more detailed look at the marshaling and unmarshaling of XML, including the different ways it can be done.

Marshaling Objects to XML

In the previous sections, we touched on the render artist as XML expression used to marshal objects into XML in one line of code. If you take a look back at Listing 15-9, the XML is produced by Grails' built-in converters in the grails.converters package. Notice how the albums collection has been marshaled into a set of identifiers only. The client could use these identifiers to utilize a separate web service to obtain the XML for each Album. Alternatively, you could use the converters provided in the grails.converters.deep package that traverse the relationships of a domain class, converting each into XML. All you need to change is the import at the top of the ArtistController class to the following:

import grails.converters.deep.*

The downside is, of course, that you get a much larger XML response, an example of which is shown in Listing 15-16, shortened for brevity.

Listing 15-16. Marshaling XML with the Deep Converter

<?xml version="1.0" encoding="UTF-8"?>
<artist id="4">
  <albums>
    <album id="4">
      <artist reference="/artist"/>
      <dateCreated>2008-08-04 21:05:08.0</dateCreated>
      <genre>Rock</genre>
      <lastUpdated>2008-08-04 21:05:08.0</lastUpdated>
      <price>10.99</price>
      <songs>
        <song id="37">
          <album reference="/artist/albums/album"/>
          <artist reference="/artist"/>
          <dateCreated>2008-08-04 21:05:08.0</dateCreated>
          <duration>430346</duration>
          <genre>Rock</genre>

          <lastUpdated>2008-08-04 21:05:08.0</lastUpdated>
          <title>Knocked Up</title>
          <trackNumber>1</trackNumber>
          <year>2007</year>
        </song>
        ...
      </songs>
      <title>Because of the Times</title>
      <year>2007</year>
    </album>
  </albums>
  <dateCreated>2008-08-04 21:05:08.0</dateCreated>
  <lastUpdated>2008-08-04 21:05:08.0</lastUpdated>
  <name>Kings of Leon</name>
</artist>

The upside is that the client gets a lot more information, which can be parsed and dealt with. Returning to the Grails console, try the script in Listing 15-17.

Listing 15-17. Using the Deep Converters Results

url = new URL("http://localhost:8080/gTunes/music/Kings%20Of%20Leon")

conn = url.openConnection()
conn.addRequestProperty("accept","application/xml")

artist = new XmlSlurper().parse(conn.content)

println "Artist Name = ${artist.name}"
println "Albums ---"
for(album in artist.albums.album) {
     println "Album Title = $album.title"
     println "Songs ---"
     album.songs.song.eachWithIndex { song, i ->
         println "${i+1}) $song.title"
     }
}

Notice how in Listing 15-17 you can find out not only about the Artist but also about all of their albums and the songs within those albums. The output from running this script is something like this:


Artist Name = Kings of Leon
Albums ---
Album Title = Because of the Times
Songs ---
1) Knocked Up
2) Charmer
...

Of course, the XML in Listing 15-16 may not be optimal because it contains a lot of data that the client may not need. Luckily, Grails also provides a simple way to marshal XML using a builder approach. Listing 15-18 shows the ArtistController class using the render method's capability to take a closure that represents the builder code needed to output XML.

Listing 15-18. Using an XML Builder to Output XML

class ArtistController {
    def show = {
        def a = params.artistName ? Artist.findByName(params.artist) :
                                        Artist.get(params.id)

        if(a) {
            withFormat {
              html artist:a, albums:a?.albums
              xml {
                render(contentType:"text/xml") {
                    artist(name:a.name) {
                        for(alb in a.albums) {
                            album(title:alb.title,
                                  year:alb.year,
                                  genre:alb.genre,
                                  price:alb.price) {
                                for(s in alb.songs) {
                                    song(title:s.title,
                                         number:s.trackNumber,
                                         duration:s.duration)
                                }
                            }
                        }
                   }
                }
              }
            }
        }
        else {
            response.sendError 404
        }
    }
}

To trigger the builder, you can use the render method, passing a contentType argument with a value of text/xml and a closure containing the builder code. The way the builder works is that each method name relates to an XML element. You'll notice from the code in Listing 15-18 that you have to be very careful not to define local variables using names you plan to use for XML elements; otherwise, Groovy will try to invoke them, thinking the variable is a closure. Nevertheless, you can see the result of the code in Listing 15-18 in Listing 15-19.

Listing 15-19. Output Using the Builder Approach


<?xml version="1.0"?>
<artist name="Kings of Leon">
    <album title="Because of the Times" year="2007" genre="Rock" price="10.99">
        <song title="Knocked Up" number="1" duration="430346"/>
        <song title="Charmer" number="2" duration="176893"/>
        ...
    </album>
</artist>

As you can see, the XML in Listing 15-19 is far more concise than that produced by the deep converter. Of course, it depends very much on your domain model. For most common cases, the grails.converter package is fine; however, if you do need fine-grained control over the XML produced, then the builder approach is a good alternative.

Marshaling Objects to JSON

As mentioned previously, REST is not limited to XML as a transport medium. JSON is a popular choice for REST web services that have many Ajax clients because of the ease with which it is possible to parse JSON using JavaScript—somewhat unsurprising given JSON is native JavaScript itself.

Fortunately, Grails makes it pretty easy to convert objects and other data structures to JSON using the grails.converters package. Listing 15-20 shows how you can use the render object as JSON expression to output JSON.

Listing 15-20. Dealing with the all Format

import grails.converters.*
...
withFormat {
    html artist:artist, albums:artist?.albums
    all artist:artist, albums:artist?.albums
    xml { render artist as XML }
    json { render artist as JSON }
}

Using file extension content negotiation, if you open a browser and hit the URL http://localhost:8080/gTunes/music/Kings Of Leon.json, Grails will return a JSON response. Depending on your browser, you may be asked to download the file, since the rendering of JSON is not typically supported by browsers in the same way XML is. Nevertheless, Grails will do its best to marshal whatever you pass to the render method into appropriate JSON, an example of which is shown in Listing 15-21.

Listing 15-21. Example JSON Response


{ "id":26,
  "class":"Artist",
  "albums":[{"class":"Album","id":4}],
  "dateCreated":"2008-08-04T21:05:08Z",
  "lastUpdated":"2008-08-04T21:05:08Z",
   "name":"Kings Of Leon"
}

So, now that you have some JSON, what conceivable benefit does it have over XML? Well, compared to the angle-bracketed XML, it is a little terser. However, the main benefit is to Ajax clients. Using a library like Prototype, it is trivial to parse the JSON in Listing 15-21, as shown in Listing 15-22.

Listing 15-22. Parsing JSON on the Client

new Ajax.Request('http://localhost:8080/gTunes/music/Kings Of Leon.json', {
  method:'get',
  requestHeaders: {Accept: 'application/json'},
  evalJSON: true,
  onSuccess: function(response){
    var artist = response.responseJSON;

    alert("Artist Name = " + artist.name);
  }
});

Compare the simplicity of evaluating a block of JSON to the pain of JavaScript DOM programming, and you will realize that JSON is certainly the better choice if your primary audience is Ajax clients. Furthermore, many popular Ajax toolkits, such as Yahoo UI and Ext-JS, allow you to use JSON data sources to populate rich components such as dynamic data tables, which may influence your choice in deciding whether to use JSON.

As well as rendering simple responses, the JSON converter, like the XML converter, also supports deep nested graphs of objects by changing the import to the grails.converters.deep package:

import grails.converters.deep.JSON

Grails also features a builder for constructing custom JSON responses, similar to the XML builder demonstrated in Listing 15-23.

Listing 15-22. Using the JSON Builder

..
withFormat {
    ...
    json {
        render(contentType:"text/json") {
              name a.name
              albums {
                   for(alb in a.albums) {
                       album name:alb.title
                   }
             }
        }
    }
}

As you can see, to trigger the JSON builder, you can pass the contentType parameter with a value of text/json or application/json. Then, within the body of the closure passed as the last argument, you can construct the JSON. Each method call in the JSON builder creates a new entry in the JSON object. You can create JSON arrays by passing a closure to a method and invoking a method for each array entry. Listing 15-24 shows the result of the JSON builder notation in Listing 15-23.

Listing 15-24. Result of Using the JSON Builder


{
"name":"Kings of Leon",
"albums":[ {"name":"Because of the Times"},
            {"name":"Aha Shake Heartbreak"} ]
}

Unmarshaling XML or JSON

Everything you have seen so far is modeled around the use of the HTTP GET method to read data from a REST web service. GET requests in REST are undoubtedly the most common; however, many REST web services also allow users to perform write operations on the server. A key principle of REST is that a GET request should never cause the state of the server to change. Other HTTP methods such as POST, PUT, and DELETE should be used in a REST model to perform write operations.

Many public web services that claim to use a RESTful approach in fact ignore this philosophy and design everything around the GET method. A GET is a lot easier to interact with because you can simply type the URL of the web service into your browser to issue a GET request. Other kinds of requests such as POST, PUT, and DELETE, however, require you to use HTTP utilities such as the Firefox Poster plugin or Fiddler, an HTTP debugging proxy, for Windows machines.

Nevertheless, it is best practice to follow the REST philosophy. Modeling everything around GET could be very damaging if you have certain GET requests that fundamentally change the data on your system. Web spiders, such as Google's search engine crawler, could quite easily step on the toes of your application by inadvertently sending GET requests to your web services! In this book, we'll be following the REST philosophy as it was designed to be implemented, even if it's a bit fussier.

Another great thing about REST is that as soon as you read data from a REST web service, you implicitly know how to perform updates to REST resources. Remember, REST stands for Representational State Transfer. This implies that when a REST web service sends you some data in XML or JSON, in order to perform a write operation all you need to do is send the changed data back in the same form it was sent to you.

Let's start by looking at the POST request first. In the context of REST, the POST method is used when a web service user wants to update data. For example, assuming you're using the render album as XML approach, if you access one of the albums from the gTunes application using the RESTful paths you established earlier, you'll get some XML back like that shown in Listing 15-25.

Listing 15-25. XML Returned from a GET Request


<?xml version="1.0" encoding="UTF-8"?>
<album id="12">
  <artist id="26"/>
  <dateCreated>2008-08-21 14:26:40.0</dateCreated>
  <genre>Alternative &amp; Punk</genre>
  <lastUpdated>2008-08-21 14:26:40.0</lastUpdated>
  <price>8.99</price>
  <songs>
    <song id="134"/>
    ...
  </songs>
  <title>Aha Shake Heartbreak</title>
  <year>2004</year>
</album>

To get the XML in Listing 15-25, you can access the URI /music/Kings%20Of%20Leon/ Aha%20Shack%20Heartbreak.xml using file extension content negotiation. Now, immediately you know how to update the data because the format has been sent to you in the GET request. But here is the catch. How do you test sending POST data to the server? Unlike sending a GET request, you can't just type the URI into the browser. To send a POST request, you're going to need a little help from the Firefox Poster plugin available from https://addons.mozilla.org/en-US/firefox/addon/2691.

Once installed, the Poster plugin will add a little "P" icon into the Firefox system tray, as shown in Figure 15-2. Image:

image

Figure 15-2. The Poster plugin tray icon

When you click the Poster icon, it will load a new window separate to the main Firefox window that contains the features of the Poster plugin. Fundamentally, it allows you to specify a URL to send a request to, plus a bunch of other stuff like the HTTP method, any content to send, and so on. Figure 15-3 shows the Poster window with the URL to the XML from Listing 15-25 specified.

image

Figure 15-3. The Poster plugins main window

In the "Actions" pane, you can add headers like the ACCEPT header by selecting the "Headers" drop-down list and clicking the "Go" button. Figure 15-4 shows how to specify an ACCEPT header of text/xml.

image

Figure 15-4. Specifying an ACCEPT header with the Poster plugin

Once the necessary ACCEPT headers and parameters have been specified, you can send a request by choosing the HTTP method from the drop-down box in the "Actions" panel and hitting the "Go" button. You'll then get the response popping up in a new window showing the XML coming back from the server. Figure 15-5 shows the same response from Listing 15-25 appearing in the Poster plugin's response window.

Now here's the trick to send data back to a REST service. All you need do is copy the text from the response shown in Figure 15-5 and paste it into the Poster plugin's "Content to Send" field. Then simply modify the data to reflect the changes you want to make. For example, if you want to change the genre from Alternative & Punk to simply Rock, you could use the XML in Listing 15-26 with the changes from Listing 15-25 highlighted in bold.

image

Figure 15-5. The Poster plugins response window

Listing 15-26. Updating the XML to Send to a REST Service

<?xml version="1.0" encoding="UTF-8"?>
<album id="12">
  <artist id="26"/>
  <dateCreated>2008-08-21 14:26:40.0</dateCreated>
  <genre>Rock</genre>
  <lastUpdated>2008-08-21 14:26:40.0</lastUpdated>
  <price>8.99</price>
  <songs>
    <song id="134"/>
    ...
  </songs>
  <title>Aha Shake Heartbreak</title>
  <year>2004</year>
</album>

Finally, to send the request use the first drop-down box in the "Actions" panel, change the method to the POST request, and hit the "Go" button. Unfortunately, in this case, the response from the server is a 404. Why? Well, currently the gTunes application can deal with GET requests but not POST requests. If you recall, the URL mapping from Listing 15-2 mapped POST requests onto an action called update, which doesn't exist yet.

Let's add the code necessary to implement the update action. Listing 15-27 shows the complete code, which we will step through in a moment.

Listing 15-27. Handling POST Requests in a REST Web Service

1 def update = {
2       def album = Album.get(params['album']?.id)
3        if(album) {
4            album.properties = params['album']
5            album.save()
6            withFormat {
7                html {
8                    render(view:"show", [album:album, artist:album.artist])
9                }
10                xml {
11                    if(!album.hasErrors()) {
12                        render album as XML
13                    }
14                    else {
15                        render album.errors as XML
16                    }
17                }
18            }
19
20        }
21        else {
22            response.sendError 404
23        }
24    }
25 }

Listing 15-27 is one of the longer listings you've seen so far in the book and there is a lot going on there, so we'll walk you through the code so you can understand what it is doing. First, on line 2, the Album instance is obtained using the id of the album contained within the params object:

2        def album = Album.get(params['album']?.id)

But hold on. Aren't you dealing with an XML request here? Where are the reams of XML parsing code? And where did this magical album within the params object come from? Quite simply, when Grails detects an incoming XML request, it will automatically parse it and configure the params object based on the contents of the XML. The power of this pattern is that as far as you are concerned, dealing with an XML (or JSON) request is no different from dealing with a regular form submission.


Note Automatic unmarshaling works only with XML that matches the conventions used within the render as XML and render as JSON automatic marshaling capabilities. If you are using a custom format, then it is your responsibility to unmarshal appropriately.


You can submit the same request to the update action using form data that starts with the album prefix. Remember how we mentioned that REST models the natural behaviors of the Web? Here you have a prime example of how Grails embraces that by allowing you to eliminate the need to differentiate between regular form submissions and REST web service requests. Another example of this can be seen on line 5, where Grails' normal data-binding pattern, which you learned in Chapter 4, is used to update the Album instance:

4            album.properties = params['album']

Then on line 5, the Album instance is saved:

5            album.save()

With that done, it's time for the withFormat method to do its thing and deal with both HTML and XML formats on line 6:

6            withFormat {

In the case of HTML, for the moment it just renders the show.gsp view again:

7                html {
8                    render(view:"show", [album:album, artist:album.artist])
9                }

The show.gsp view could be updated to utilize the <g:renderErrors> tag to display any update errors to the user. In the case of XML, the logic is a little different. If there are no errors, then you can simply send the Album back to the caller of the REST API with the changes reflected on lines 10 to 13:

10                xml {
11                    if(!album.hasErrors()) {
12                        render album as XML
13                    }
                    ...
18                 }

However, if there are validation errors, you can send an error response using the errors property of the Album instance. By using the render method, you can automatically marshal errors to XML:

15                        render album.errors as XML

Now you can try calling the update action via a REST web service. First, return to the Fire-fox Poster plugin, and try to resubmit the POST request. This time when you submit the POST request, you can see the <genre> element in the XML has been updated in the response! If you tried to send an invalid value such as a blank Album title to the web service, you would get an error response like the one shown in Listing 15-28.

Listing 15-28. An Error Response from a REST Web Service


<errors>
  <error object= "com.g2one.gtunes.Album"
         field= "title"
         message= "Property [title] of class..."
         rejected-value="" />
</errors>

And with that, you have added support, not only for reading information about albums and artists via a REST API but also for updating album details. Feel free to explore the capability further by implementing support for updating artists and songs via POST requests. This exercise is similar in each instance and will give you good practice in using Grails' REST support.

Note that adding support for PUT and DELETE is largely similar to what you've already seen. In the case of a PUT request, instead of looking up an existing instance, as you saw on line 3 of Listing 15-27, you would create a brand new instance by passing the params object into the constructor, as shown in Listing 15-29.

Listing 15-29. Binding XML Data to New Instances

def save = {
    def album = new Album(params["album"])
    ...
}

The remaining code to deal with PUT requests is much like the update action in Listing 15-27. As for the DELETE requests, you just have to obtain the instance and call the delete() method. It's pretty simple really. However, one thing we haven't yet discussed is security.

REST and Security

In Chapter 14, you used the JSecurity framework to secure the gTunes application. Having an open REST API that allows any user to update the data in the gTunes application is probably not desirable. There are a number of different ways to implement security with REST. In fact, the issue of security in REST is one of the hottest points in the SOAP vs. REST debate, because— unlike SOAP, which defines a standard for security called WS-Security—there is no standard for REST security.

If you plan to maintain a completely stateless client API, then you could use request headers such as the Authorization HTTP header with some form of token-based authentication. This is a model followed by Google and Amazon in their REST APIs. Alternatively, you could use Secure Sockets Layer (SSL) communication over HTTPS with basic authentication provided by the web server. The topic of security in REST is broad and has many ramifications.

Assuming it's OK to maintain stateful clients, then another, possibly simpler, alternative is to use the JSecurity framework and provide a REST API onto your application's login system. The downside is that clients would be required to support cookies in order for the server to be aware that the client is logged in. The Apache Commons HttpClient (http://hc.apache.org/httpclient-3.x/authentication.html) project is an example of a client-side library that supports cookies, which clients can take advantage of.

Atom and RSS

Atom and RSS are two competing standards to allow the publishing of web feeds. The two formats have proven very popular with many applications, including modern web browsers that support RSS and Atom feeds to provide news headlines, as well as with blog aggregators. Nearly every website you visit nowadays has either an RSS or Atom feed that you can subscribe to, to get the latest news or information. Although the provision of RSS or Atom feeds is not a web service in the traditional sense, it is very similar in that the mechanics involve the exchange of XML data over HTTP.

Moreover, Google is actually standardizing on Atom and the Atom Publishing Protocol (APP) as the format used in all of its web services APIs, so there is clearly a lot of crossover between REST and the syndication formats Atom and RSS. Currently, Grails doesn't provide support for RSS and Atom out of the box, but an excellent Feeds plugin is available in the plugin repository. In the following sections, we'll be covering how to install the Feeds plugin and provide RSS and Atom feeds that show the latest additions to the gTunes library.

To get started, you first need to install the Feeds plugin by running the following command:

$ grails install-plugin feeds

Creating RSS and Atom Feeds

What the Feeds plugin does is add functionality to the render method to facilitate the rendering of RSS and Atom feeds. Under the covers, the plugin is using the popular Rome library (http://rome.dev.java.net/) to produce the feeds; Rome is yet another example of how Grails promotes reuse of the existing Java ecosystem. Let's look at an example in code of how to use the Feeds plugin; see Listing 15-30.

Listing 15-30. Rendering RSS and Atom Feeds with the Feeds Plugin

1 def latest = {
2    def newestAlbums = Album.list(max:5, sort:"dateCreated", order:"desc")
3
4    def feed = {
5        title = "Newest Additions to gTunes"
6        link = g.createLink(controller:"store",
7                                              action:"latest",
8                                               params:[format:request.format])
9        description = "Track the newest additions to the gTunes music store"
10      for(a in newestAlbums) {
11           entry(a.title) {
12               link = g.createLink(controller:"album", action:"show", id:a.id)
13               g.render(template:"/album/album", model:[album:a, artist:a.artist])
14           }
15       }
16    }
17
18    withFormat {
19        rss { render(feedType:"rss", feed) }
20        atom { render(feedType:"atom", feed) }
21    }
22 }

The code in Listing 15-30 adds a new action to the StoreController that provides RSS and Atom feeds of the five most recent additions to the albums within gTunes' library of music. Once again, the code takes advantage of Grails' content negotiation feature described earlier in the chapter to deliver both RSS and Atoms feeds. First, on line 2, the five most recent albums are obtained using GORM's list method:

2    def newestAlbums = Album.list(max:5, sort:"dateCreated", order:"desc")

Then on line 4, the feed is constructed using the builder syntax defined by the Feeds plugin:

4    def feed = {

The Feeds plugin uses a domain-specific language (DSL) to wrap the inner workings of the Rome API. Your job is limited to specifying the feed title, description, and entries.


Tip For a more comprehensive overview of the syntax supported by the Feeds plugin, refer to the documentation available at http://grails.org/Feeds+Plugin.


Lines 5 to 9 do the job of setting a title for the feed, as well as a more detailed description and a link back to the feed URL:

5        title = "Newest Additions to gTunes"
6        link = g.createLink(controller:"store",
7                                             action:"latest",
8                                             params:[format:request.format])
9        description = "Track the newest additions to the gTunes music store"

Notice how on line 6 you can take advantage of the <g:createLink> tag called as a method to create a link back to the feed with the appropriate format prepopulated. In this example, title and description have been hard-coded, but you could just as easily pull this information from an i18n message bundle using the <g:message> tag called as a method, as described in Chapter 7:

title = g.message(code:"gtunes.latest.feed.title")

With all the metadata provided to the feed, the next job is to create the entries for the feed. The syntax used by the Feeds plugin is to call a method called entry, passing in the entry title and a closure. Within the body of the closure, you are able to set metadata about the entry, including a link back to it. Finally, the return value of the closure is used to populate the markup contained within the body of the feed entry. You can see the mechanics of this in action on lines 11 to 14:

11            entry(a.title) {
12                link = g.createLink(controller:"album", action:"show", id:a.id)
13                g.render(template:"/album/album", model:[album:a,
artist:a.artist])
14            }

Notice how once again you can use the <g:createLink> tag to create a link to the album. Also, to populate the body content of the entry, you can take advantage of the <g:render> tag called as a method to render the grails-app/albums/_album.gsp template, which already knows how to format an album appropriately. With that done, it's time to use the feed, and once again you see the withFormat method in action on line 18:

18    withFormat {
      ...
21    }

However, unlike in previous examples, instead of handling HTML or XML, this example uses content negotiation to deliver RSS and Atom formats:

19        rss { render(feedType:"rss", feed) }
20        atom { render(feedType:"atom", feed) }

There are a few key things to notice about the previous code. First, as you can see within the withFormat method, you can enable the handling of RSS and Atom feeds by calling the rss and atom methods, respectively, passing in a closure that should be invoked in each case. Within the body of each closure, you can see the render method used in combination with the feedType argument to specify either rss or atom. To maintain the DRYness15 of the code, notice how you can pass the same reference to the feed closure regardless of whether you are rendering an Atom or an RSS feed.

One final thing to do is to create a new URL mapping in the grails-app/conf/UrlMappings. groovy file so that the feeds are exposed:

"/store/latest"(controller:"store",action:"latest")

Your efforts are complete. To access the RSS feed, you can use the URL http://localhost:8080/gTunes/store/latest.rss, while the Atom feed can be accessed by changing the .rss extension to .atom. If you access the RSS feed within Firefox, which supports RSS, you'll get a page rendered like the one in Figure 15-6.

image

Figure 15-6. Firefox rendering of an RSS feed

RSS and Atom Link Discovery

Another feature of most RSS and Atom-enabled browsers is the ability to automatically discover feed links for the currently viewed page. For example, if you go to http://news.bbc.co.uk in Fire-fox, you'll notice a little blue feed icon appear in the address bar, as shown in Figure 15-7.

image

Figure 15-7. Firefox RSS feed detection in action

It may seem like magic, but the way it works is that developers need to provide the necessary HTML <meta> headers that link to the RSS or Atom feed. Only then will a browser such as Firefox discover the feed. Luckily, the Feeds plugin provides support for doing just this using the <feed:meta> tag. Say, for example, you wanted the RSS or Atom icon to appear in the browser when users visited the gTunes store; you could quite easily enable this by modifying the grails-app/views/layouts/storeLayout.gsp layout as shown in Listing 15-31.

Listing 15-31. Providing RSS and Atom Metadata

<html>
    <head>
        <feed:meta kind="rss"
                               version="2.0"
                               controller="store"
                               action="latest"
                               params="[format:'rss']"/>
        <feed:meta kind="atom"
                               version="1.0"
                               controller="store"
                               action="latest"
                               params="[format:'atom']"/>
         ...
    <head>
    ...
</html>

Now if you go to http://localhost:8080/gTunes/store, you'll see the same browser address bar links in Firefox as you did on the BBC! And with that, it is now time to look at a different web services paradigm via the SOAP specifications.

SOAP

SOAP is a specification for web services that originated in a joint Microsoft and IBM effort. SOAP was originally an acronym for Simple Object Access Protocol; however, after discovering it wasn't simple or an access protocol and didn't have anything to do with objects, the creators decided to ditch the acronym, so now it's just called SOAP.

Although REST is designed to be used with simple tools like your browser, SOAP as a technology cannot be used effectively without good tooling and technological support. The premise of SOAP is that, through the use of tools, you generate a web service descriptor using the Web Services Description Language (WSDL). SOAP clients can then use the WSDL to generate (using tooling support) a client that is capable of invoking the SOAP service in their language of choice.

Although REST is all about resources and transferring XML representations of those resources, SOAP is fundamentally a Remote Procedure Call (RPC) technology. Instead of being an architectural pattern like REST, it encourages developers to continue to think in objects and function calls. It just so happens that those objects and function calls are remote web services.

To support this RPC model, the SOAP specification includes the facility to describe within the WSDL (in XML Schema) how objects should be marshaled to and from XML. Each data type is described in XML Schema, and Java tools digest the WSDL and attempt to automatically marshal objects to and from XML using the schema.

The primary goal of SOAP is to enable interoperability between different languages and tools using XML as the transport medium, something that REST achieves just as well. However, SOAP also includes a number of complementary standards, under the WS-* banner, that cover everything from security and transactions to management and discovery. Furthermore, unlike REST, which is primarily based on HTTP, SOAP doesn't mandate the protocol and could be used over a range of protocols including SMTP and FTP. All in all, it's a lofty goal; unfortunately, the various SOAP specifications have gone through a number of drafts, and the implementors of the specifications have continually had to play catch-up.

To make matters worse, it has taken a while for SOAP vendors and users to decide what the best practices are for implementing SOAP (see http://www.ibm.com/developerworks/webservices/library/ws-whichwsdl/). Some early adopters settled on a pattern for binding called RPC/encoded (rpc-enc) for the SOAP message bodies. Later, another pattern called document/literal (doc-lit) became popular. Currently, four styles are in existence:

  • RPC/encoded (rpc-enc)
  • RPC/literal (rpc-lit)
  • Document/encoded (doc-enc)
  • Document/literal (doc-lit)

The result is that not all SOAP implementations can communicate with one another. To mitigate this problem, a Web Services Interoperability (WS-I, http://www.ws-i.org/) group was formed that is designed to make sense of all the SOAP standards from the W3C and Oasis and provide recommendations as to what can be used and what cannot because of problems with interoperability. All in all, SOAP could be viewed as a bit of a mess, but the good news is things can only get better, and the SOAP stacks are improving. There are advantages to using SOAP over REST, including a defined specification for security called WS-Security. Additionally, there are many existing adopters of SOAP, so it isn't going away anytime soon.

Competition is good, and REST has helped drive massive improvements in the SOAP stacks as they play catch-up to the simplicity provided by REST.

In the following sections, we'll cover the different ways you can implement SOAP web services in Grails and also how you can invoke SOAP web services from Grails.

SOAP Web Services via Plugins

If you are looking to expose a SOAP service with Grails, you are currently rather spoiled for choice. Three plugins add the capability to expose SOAP services, each using a different underlying framework. The plugins are as follows:

  • XFire Plugin (http://www.grails.org/XFire+plugin): The XFire plugin builds on the original XFire project (http://xfire.codehaus.org/), allowing you to expose Grails services as SOAP services. The XFire plugin is, as of this writing, the most mature of the SOAP plugins.
  • Axis 2 Plugin (http://www.grails.org/Apache+Axis2+Plugin): The Axis 2 plugin builds on the Apache Axis 2 framework (Axis 1 was the first open source SOAP stack available for Java). The plugin works by integrating the WSO2 Web Services for Spring project (http://wso2.org/projects/wsf/spring) that integrates Axis 2 with Spring. Since Grails is built on Spring, anything that can integrate with Spring can integrate with Grails.
  • Metro Plugin (http://jax-ws-commons.dev.java.net/grails/): This is a plugin that integrates with Metro (http://metro.dev.java.net/), the web services stack that is part of the Glassfish umbrella project. The Metro plugin allows you to use standard JSR-224 Java API for XML-based Web Services (JAX-WS) annotations on Grails service classes to expose a SOAP web service.

So, you have several options. Each is pretty trivial to use, but we'll take a look at how to go about using the XFire plugin as an example. First you need to install the plugin by running the grails install-plugin command as follows:

$ grails install-plugin xfire

Once the plugin is installed, it works by integrating with the Grails service classes that were described in Chapter 11. The way it does this is by making each service available as a SOAP web service under the /services URI. To ensure this URI is not dealt with by Grails, you need to add a constraint to the default URL mapping in grails-app/conf/UrlMappings.groovy, as shown in Listing 15-32.

Listing 15-32. Changing the Grails URL Mappings to Exclude the /services URI

"/$controller/$action?/$id?"{
     constraints {
           controller(matches:/.*[^(services)].*/)
     }
}

As you can see in Listing 15-32, by using the matches constraint you can tell Grails not to match the /services URI. Now, let's try to create an example SOAP service by running the following command:

$ grails create-service com.g2one.gtunes.Album

You'll end up with a new service class called AlbumService located in the grails-app/ services directory under the package com.g2one.gtunes. Now try to write a method in the AlbumService that finds all the album titles for a given artist. Listing 15-33 shows the code for the AlbumService class.

Listing 15-33. The AlbumService Class

package com.g2one.gtunes
class AlbumService {

    String[] findAlbumsForArtist(String artistName) {
        def artist = Artist.findByName(artistName)
        def albums = []
        if(artist) {
            albums = Album.findAllByArtist(artist)
        }
        return albums.title as String[]
    }
}

You can write a simple unit test that tests the behavior of this method using the generated test in the test/unit directory called AlbumServiceTests. Listing 15-34 shows an example test for the findAlbumsForArtist method.

Listing 15-34. Testing the Service Code

import grails.test.*
void testFindAlbumsForArtist() {
    def artist = new Artist(name:"Beck")
    MockUtils.mockDomain(Artist, [artist])
    MockUtils.mockDomain(Album, [new Album(title:"Odelay", artist:artist),
                                 new Album(title:"Guero", artist:artist)])

    def albumService = new AlbumService()

    def results = albumService.findAlbumsForArtist("Beck")
    assertEquals 2,results.size()
    assertEquals "Odelay", results[0]

    results = albumService.findAlbumsForArtist("Rubbish")

    assertEquals 0, results.size()
}

With that done, it's time to utilize the features of the XFire plugin. All you need to do to expose the AlbumService as a SOAP web service is to add a single line to the AlbumService class definition as follows:

static expose = ['xfire']

What this says is that you want to "expose" the AlbumService class to the world as a web service using the XFire plugin. You'll see this convention used elsewhere in Grails and its plugins. For example, using the Remoting plugin (http://grails.org/Remoting+Plugin), which allows you to expose Grails services over the Remote Method Invocation (RMI) standard, is configured as follows:

static expose = ['rmi']

To test the SOAP web service, run Grails with the grails run-app command. The XFire plugin uses the /services URI to map to SOAP web services. In the case of the AlbumService, the full URI to the exposed web service is /services/album where the /album part is taken from the name of the service. To get the WSDL for the AlbumService, you can access the URL http://localhost:8080/gTunes/services/album?wsdl. The XFire plugin generates the WSDL for each service automatically at runtime. The WSDL itself is a rather long and unwieldy XML format that is far too long to list here—heaven knows how authors of SOAP books manage! Nevertheless, Listing 15-35 shows a much shortened version of the XML you're likely to get back.

Listing 15-35. Example Generated WSDL


<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions targetNamespace="http://gtunes.g2one.com"
                  xmlns:tns="http://gtunes.g2one.com"
                  xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/"
                  xmlns:soap12="http://www.w3.org/2003/05/soap-envelope"
                  xmlns:xsd="http://www.w3.org/2001/XMLSchema"
                  xmlns:soapenc11="http://schemas.xmlsoap.org/soap/encoding/"
                  xmlns:soapenc12="http://www.w3.org/2003/05/soap-encoding"
                  xmlns:soap11="http://schemas.xmlsoap.org/soap/envelope/"
                  xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
  <wsdl:types>
    <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
            attributeFormDefault="qualified"
            elementFormDefault="qualified"
            targetNamespace="http://gtunes.g2one.com">
        <xsd:element name="findAlbumsForArtist">
            <xsd:complexType>
            ..
            </xsd:complexType>
            ..
        </xsd:element>
        ...
    </xsd:scema>
       ...
  </wsdl:types>
   ...
</wsdl:definitions>

As you can see, it's not something that mere mortals should have to digest given that even the namespace definitions take ten lines. Fortunately, SOAP is designed to be used in conjunction with good tools and frameworks—enter the Groovy-WS project.

Calling SOAP from the Client

Unlike REST, calling SOAP services requires jumping through several hoops. It is worth investigating what SOAP tools are available on your platform. On the Mac, there is the excellent Mac SOAP Client project (http://code.google.com/p/mac-soapclient/) that provides a useful graphical utility for testing SOAP web services. Figure 15-8 shows an example of its usage. Notice how you can specify the URL to the WSDL, which is then automatically digested by the Mac SOAP client.

image

Figure 15-8. The Mac SOAP client

As you can see, you can specify in the drop-down the method of the SOAP service to execute and what parameters to pass. The tabs at the bottom allow you to see the outgoing request and the response from the SOAP service. That's all very useful for debugging your SOAP services, but let's look at how you can call a SOAP service from Groovy. To do so, you can use the Groovy-WS project available at http://groovy.codehaus.org/GroovyWS.


Note The current XFire plugin for Grails is based on the original XFire project, while Groovy-WS is based on Apache CXF, which is the successor to XFire. As of this writing, there isn't a CXF plugin for Grails. However, it can be configured manually as described in the "Grails + CXF Example" tutorial at http://docs.codehaus.org/pages/viewpage.action?pageId=85983334.


Two downloads are available:

  • The full JAR containing all the required dependencies for both the server and client portions of Groovy-WS including the Servlet APIs. If you plan to use Groovy-WS from Grails, then this JAR will not work because it embeds the Servlet APIs and its own version of Jetty (Grails' default container), which causes conflicts with any web application deployment (including Grails).
  • A trimmed-down JAR that contains Groovy-WS and all its dependencies, excluding the Servlet APIs and Jetty server.

For this example, we'll demonstrate calling a SOAP service from the console, so either JAR will do. Simply download one of the JARs, and then run the Groovy console with the following command:

$ groovyConsole -cp /path/to/groovyws-all-0.3.1.jar

Now try the script in Listing 15-36.

Listing 15-36. Calling a SOAP Web Service

import groovyx.net.ws.WSClient

def proxy = new WSClient("http://localhost:8080/gTunes/services/album?wsdl",
                          this.class.classLoader)

albums = proxy.findAlbumsForArtist("Tracy Chapman")

println "Found (${albums.string.size()}) Albums"
println "-------------"
albums.string.each {
    println it
}

The example in Listing 15-31 uses the Groovy-WS project's dynamic SOAP client called groovyx.net.ws.WSClient that automatically digests the WSDL and creates an appropriate interface for interacting with it. Using the proxy created by WSClient, you can invoke the findAlbumsForArtist method as if it were a regular method.

Oddly, the JAXB specification requires that array types in Java be returned as ArrayOf<Type> definitions on the client. Hence, the findAlbumsForArtist method returns a type that is actually ArrayOfString and not a String[] as you might expect. The intricacies of how SOAP and SOAP frameworks marshal objects from one type to another from client to server is beyond the scope of this book. To obtain the actual String[], you can call the ArrayOfStrings.getString() method, as shown in the example in Listing 15-31. To wrap things up, Figure 15-9 shows what the result of this script looks like in the Groovy console.

image

Figure 15-9. Calling a SOAP service from the Groovy console

Summary

Once again, a lot of ground has been covered in this chapter. Now you should have a good understanding of the options available to you when developing web services on the Grails platform. Whether you choose REST or SOAP depends on a number of factors, some possibly outside your control. Nevertheless, you are safe in the knowledge that there is good support for both paradigms in Grails.

In your exploration of REST, you learned how to leverage Grails content negotiation features to deal with REST requests. You explored how to marshal both XML and JSON and how to invoke REST web services from Groovy and JavaScript clients. On the SOAP side, you discovered how to expose a Grails service as a SOAP service and how to use the Groovy-WS project to invoke SOAP web services. You even got to explore a little bit outside the realms of strict web services by creating RSS and Atom feeds for the gTunes application.

There is still ground to be covered, however, and in the next chapter you'll be learning how to take advantage of Grails' close integration with the Spring framework. Stay tuned.



11. REST is a broad subject, the full details of which are beyond the scope of this book, but we recommend you read Roy Fielding's original dissertation on the subject at http://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm.

12. Atom refers to a pair of related standards, the Atom Syndication Format and Atom Publishing Protocol (APP); see http://en.wikipedia.org/wiki/Atom_(standard).

13. Multipurpose Internet Mail Extensions (MIME) is an Internet standard for describing content types; see http://en.wikipedia.org/wiki/MIME.

14. The Wireless Application Protocol (WAP) is a wireless communication standard to enable Internet access on mobile devices; see http://en.wikipedia.org/wiki/Wireless_Application_Protocol.

15. Don't Repeat Yourself (DRY) is an acronym used in programming circles to describe the philosophy of avoiding repetition at all costs.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset