Issuing a SOAP request and parsing a response

SOAP stands for a Simple Object Access Protocol. And, indeed, the protocol is very simple and extensible, since it only defines the container parts of the message being transferred, such as, body, header, and fault. But it does not strictly define format or validation rules for the content of the message apart from requesting the message to be XML-compatible.

Also, SOAP has several low-level protocol bindings such as, SOAP-over-HTTP, SOAP-over-SMTP, and SOAP-over-JMS. HTTP binding is the most popular choice for SOAP-based web services.

Usually, a SOAP web service is associated with a Web Service Definition Language (WSDL) and probably a set of XML Schema Definition (XSD) that more precisely define the contents of the service operation requests and responses. But strictly speaking those are not required by the SOAP standard, even though they definitely help to understand the service input and output formats.

There is also a family of WS-* (WS-I, WS-Policy, WS-Addressing, WS-Security, and so on) standards that define different aspects of web service authentication, authorization, interoperability, notification, validation, and so on, which can enrich a SOAP message with additional headers, structures, and faults.

There are plenty of libraries available out there to support different WS-* and X-* flavors, but there is no single answer (at least in the open source world) to all of them.

In essence, any SOAP request is an HTTP POST request containing a SOAP Envelope with message data and headers.

In this recipe, we will focus on constructing simple SOAP requests at the HTTP protocol level using the HTTPBuilder library that we just encountered in the previous recipe, Issuing a REST request and parsing a response.

Getting ready

For testing purposes, we will use SOAP web services hosted at http://www.holidaywebservice.com. We will try to call the GetMothersDay operation on the USHolidayDates service. The following XML snippet is the SOAP request we will send to the service:

<?xml version="1.0" encoding="UTF-8"?>
<soap-env:Envelope
 xmlns:soap-env='http://schemas.xmlsoap.org/soap/envelope/'>
  <soap-env:Header/>
  <soap-env:Body>
    <GetMothersDay
     xmlns='http://www.27seconds.com/Holidays/US/Dates/'>
      <year>2013</year>
    </GetMothersDay>
  </soap-env:Body>
</soap-env:Envelope>

As you can guess, it tries to retrieve a date of the Mother's Day for 2013.

How to do it...

Let's perform the following steps to construct our SOAP client for the holiday web service:

  1. First of all we need to @Grab and import the required classes as shown in the following code snippet:
    @Grab(
      group='org.codehaus.groovy.modules.http-builder',
      module='http-builder',
      version='0.6'
    )
    import static groovyx.net.http.Method.*
    import static groovyx.net.http.ContentType.*
    import groovyx.net.http.HTTPBuilder
  2. Then we need to create an instance of HTTPBuilder and point to our web service:
    def baseUrl = 'http://www.holidaywebservice.com/' +
                  'Holidays/US/Dates/USHolidayDates.asmx'
    def client = new HTTPBuilder(baseUrl)
  3. Now, we need to define several namespace variables to refer to during the XML building stage:
    def holidayBase = 'http://www.27seconds.com/Holidays'
    def holidayNS = "$holidayBase/US/Dates/"
    def soapAction = "$holidayBase/US/Dates/GetMothersDay"
    def soapNS = 'http://schemas.xmlsoap.org/soap/envelope/'
  4. At this point, we are ready to POST a SOAP request to the service:
    def response = client.request( POST, XML ) {
      headers = [
       'Content-Type': 'text/xml; charset=UTF-8',
       'SOAPAction': soapAction
      ]
      body = {
        mkp.pi(xml:'version="1.0" encoding="UTF-8"')
        'soap-env:Envelope'('xmlns:soap-env': soapNS) {
          'soap-env:Header'()
          'soap-env:Body' {
            GetMothersDay('xmlns': holidayNS) {
              year(2013)
            }
          }
        }
      }
    }
  5. Now, we are ready to process the response, for example, by printing the following code line:
    println response

How it works...

As you can guess, HTTPBuilder just makes a POST request. We also give a hint to HTTPBuilder that we are going to send XML data to the service. When that hint is given, the body parameter is processed with the help of StreamingMarkupBuilder (see the Constructing XML content recipe in Chapter 5, Working with XML in Groovy) and encoded.

Since the service, which we are trying to connect to, is based on SOAP 1.1, we need to add a special SOAPAction header (in SOAP 1.2 that header is no longer needed). Also, the Content-Type header is mandatory, because otherwise the web service will not recognize the type of content we are trying to submit.

The response object is of the GPathResult type, which can be navigated, searched, and printed in the same way as any other XML structure in Groovy with the help of the GPath expressions. For more information on XML processing, refer to Chapter 5, Working with XML in Groovy.

There's more...

On the Groovy's website, you can find references to two other SOAP supporting libraries: GroovySOAP and GroovyWS. Both of them are considered deprecated in favor of the groovy-wslite library (https://github.com/jwagenleitner/groovy-wslite) developed by John Wagenleitner. The library has a terrific support for SOAP features and is a bit less verbose than plain HTTPBuilder.

The following script makes use of groovy-wslite and does exactly the same as the script described previously:

@Grab('com.github.groovy-wslite:groovy-wslite:0.8.0')
import wslite.soap.*

def baseUrl = 'http://www.holidaywebservice.com/' +
              'Holidays/US/Dates/USHolidayDates.asmx'

def client = new SOAPClient(baseUrl)

def holidayBase = 'http://www.27seconds.com/Holidays'
def holidayNS = "$holidayBase/US/Dates/"
def soapAction = "$holidayBase/US/Dates/GetMothersDay"

def response = client.send(SOAPAction: soapAction) {
  body {
    GetMothersDay('xmlns': holidayNS) {
      year(2013)
    }
  }
}

println response.GetMothersDayResponse
..................Content has been hidden....................

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