Monthly Archives: November 2006

Consuming SOAP WebServices (in PHP)

SOAP and WSDL are the targets of much bashing recently. All the cool kids are building RESTful APIs, and are moving away from the “legacy” approach of using the more heavyweight webservice APIs. That said, there are many systems that expose APIs using SOAP and WSDL. Having a good process for building these and using the right tools for development is important. After much gnashing of teath and pulling out of hair, I have just come up with a process that I am happy with.

The key first tool in the toolkit is SOAPUI. This is a great Java Swing based client that makes working with WSDL almost fun. Basically you point it at the WSDL URL or file, and it generates XML requests. Extremely useful for getting an idea of what you can do with the soap (I can read the XML requests, but I don’t speak WSDL natively).

In the PHP world (and other environments) there are many cool mapping tools that will automatically convert native data types to the appropriate XML. nuSOAP does this pretty well, although it does get a bit much like hard work when using complex types. Particularly when you have arrays of complex types. A nice feature of nuSOAP is the ability to pass in an xml string. This approach, combined with PHP’s nice native support for text and strings, mixed in with the output of SOAP UI, ends up with a suprisingly simple way of working.

In PHP I can specify the following:

$xmlData=<<<EOT
<method xmlns="http://my.namespace.com">
    <name>${variableForName}</name>
</method>
EOT;

which works great when coupled with SOAP UI, because SOAPUI will generate the text within the HereDoc. We simply need to embed in the variable that we are going to use (${variableForName} in this case). In nuSOAP the call will be:

$wsdlurl = "http://url.for.wsdl/path/to/wsdl" 
$wsdl = new wsdl($wsdlurl);    
$soapclient = new nusoapclient($wsdl, true);
$soapclient->call('method', $xmlData);  

We are then simply able to pass in any desired variables as the in parameters. This works great for more complex examples, like when working with maps in OpenSymphony’s OS Workflow. (using the built-in OSWorkflow support for XFire to expose the service).

Then the XML data will be something like the following:

$xmlData=<<<EOXMLDATA
<doAction xmlns="http://workflow.opensymphony.com">
    <in0>${instance}</in0>
    <in1>${action}</in1>
    <in2>
        <entry>
            <key>mapKey</key>
            <value>${mapValue}</value>
        </entry>
        <entry>
            <key>anotherMapKey</key>
            <value>${anotherValue}</value>
        </entry>
    </in2>
</doAction>
EOXMLDATA;

This process of using SOAPUI to create the XML and then binding parameters into it is now my prefered way of working. The pain that can be caused by using automagic mapping is too great. Specifying the XML fully does look a little bit ugly, but it does simplify the process of building the system. By doing this there is less of the magic in the SOAP mapping tools being used, but less opportunity for leaky abstractions to get in the way (and given that SOAP UI does a great job of generating the XML, life is good).