April 21, 2009

Consuming SOAP Web Services in Grails

On my current project, my team has to consume numerous web services from an external, SOAP provider. This may seem trivial, but the Grails Framework provides numerous ways to expose web services, but could offer few solutions to consume the web services. I initially experimented with GroovyWS. After some success, I had to ditch it because the services that we are working with are too complex for that library.

The solution I decided to use back to Java. Since Groovy runs on the JVM, a Groovy developer is armed with the same libraries as a Java devloper. This makes the Groovy language very powerful (if it needs to be). To consume a SOAP service, import the required Java libraries - I used the Apache Commons Libraries.

import org.apache.commons.httpclient.*;

The implementation of the calls may seem primitive, but what it lacks in beauty it makes up for in speed - I was shocked at the quickness of the service calls. To call the service, we are going to pass a small snippet of XML to the web service and parse the results. First, define the url of the web service and the XML request (which I of course called payload):

def url = "http://www.webservicex.net/CurrencyConvertor.asmx?wsdl"

def payload = """
<?xml version="1.0" encoding="UTF-8" standalone="no"?><SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:s="http://www.w3.org/2001/XMLSchema" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:tns="http://www.webserviceX.NET/" xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" ><SOAP-ENV:Body><tns:ConversionRate xmlns:tns="http://www.webserviceX.NET/"><tns:FromCurrency>USD</tns:FromCurrency><tns:ToCurrency>EUR</tns:ToCurrency></tns:ConversionRate></SOAP-ENV:Body></SOAP-ENV:Envelope>
"""

Please don't be afraid of the payload. I was at first, but the ever so awesome SOAP Client is used to make SOAP requests and responses a breeze. The payload string is generated by the SOAP Client then pasted in the source code. The payload string will differ depending on what function is being used - notice in the example string that I am converting USD to EUR.

From here, we need to send the request to the server and recieve its response - hopefully a 200 response.

def method = new PostMethod(url)
def client = new HttpClient()

payload = payload.trim()
method.addRequestHeader("Content-Type","text/xml")
method.addRequestHeader("Accept","text/xml,application/xml;q=0.9")
method.setRequestEntity(new StringRequestEntity(payload))
def statusCode = client.executeMethod(method)
println "STATUS CODE : ${statusCode}"
def resultsString = method.getResponseBodyAsString()
method.releaseConnection()
return resultsString

This makes the request to the server and returns a string.

From here, we can parse the string and reap the benefits of not having to write the complex functionality that the web service provided our application.

This method of consuming a web service also appears in Scott Davis' Book, Groovy Recipes: Greasing the Wheels of Java. All I want to know is why could I not find this information 2 months ago? This book is a must for any Groovy/Grails geek.

I know this is a trivial example, but trust in this method and the the methods described in the previous post. Please post a comment if a more complex example is needed - I had a hard time finding resources when I was searching and want to help out anyone that I can.

Big thanks to the formatmysourcecodeblog for the cool source code boxes - I will definitely be using them again.

7 comments:

  1. where does groovy-ws break down on you? do you think it will get better?

    ReplyDelete
  2. Groovy-WS was a little too slow for my taste. It had trouble working with a more complex web service that I was trying to consume - it does work great for simple services.

    I do not think that there are any planned, major improvements to Groovy-WS. There are ways of consuming services using available web service plugins, but I had limited success with trying to implement them.

    ReplyDelete
  3. Nice example, Nick. Given your use of HttpClient, you might be interested in the fairly new Groovy HTTP Builder. Also, I've started using Alex Gorbatchev's SyntaxHighlighter JavaScript library for displaying source code on my blog. It does such a nice job with so many languages. I discovered, but also resolved, one wrinkle with using it on a Blogger blog.

    --Matt

    ReplyDelete
  4. Matt-

    I'll have too look into Groovy HTTP when I refactor our existing web services. Thanks for the tip.

    Also, that syntax highlighter looks great - I'll give it a try the next time I post a technical article.

    Thanks for the comment. -Nick

    ReplyDelete
  5. Hi,
    This is very nice article.
    We use httpclient extensively along with httpunit to load test websites.
    also we use it to scrape web data

    Scrappingexpert.com Web data Extraction , crawling, data mining


    thanks,
    Prat

    ReplyDelete
  6. This version works, but you need the httpcomponents 3.x!

    here is the "genius 'groovy' version":

    ReplyDelete
  7. @Prat -

    I like the idea of load testing with httpclient. That is something that is always a mystery (to me at least) until there is load on a site. I'll keep that in mind in the future - Thanks.

    ReplyDelete