New developments for ZSI
The last time ZSI was covered in this column, it was version 1.2. ZSI has enjoyed a recent spate of activity including the contributions for other developers besides the lead Rich Salz. It is now in version 1.4.1 and has added some WSDL support. Uche Ogbuji and Scott Archer take a look at these new developments and also discover a third-party wrapper option for ZSI.
The "Web Services for Python" project, which forms an umbrella for ZSI and SOAPpy, provides the best-maintained and most usable Web services tools for Python. We have looked closely at these packages previously in this column:
Since we wrote those articles, these packages have made important improvements and added features. In this article we will look at what's new with ZSI, looking to put it to work against a more industrial strength public Web service.
A look at ZSI 1.4.1
had a look at ZSI 1.4.1, testing it on Python 2.2.2. The most
significant update in ZSI is support for WSDL. There is a new ZSI class
ServiceProxy, which you initialize with the URL of a WSDL file. The documentation says it "uses a
instance to send and receive messages." If you've followed our coverage
of ZSI in this column you'll remember that ZSI has been an excellent
library for Web services that follow certain narrow rules, but
unfortunately requires a number of obscure tricks and tweaks (and more
code than you might expect) to get it to handle the general case.
it seems that ZSI can handle any Web service out there. It's just that
it doesn't take much variation before you find yourself writing all
sorts of complex code to process structures with type codes.
The root of the problem is that SOAP message structure tries to combine
the traditional rigors of RPC with the flexibility of XML. One of the
purposes of WSDL is to provide a structured-enough description of a
service's message protocol so that it allows applications to
automatically figure out things the developer would have to sort out.
The addition of WSDL support to ZSI offers the promise of reducing the
need for the developer to be too clever about interpreting the SOAP
message. Whether the Web service uses positional parameters, named
parameters, or both, and whether it uses simple, complex, or custom
data types, the WSDL file should provide the needed intelligence. As
such, it was with some anticipation that we tried
not on the sorts of toy Web services (such as the Captain Haddock
curser or the simple calendar service) we have used with ZSI in the
past, but rather one of the more useful public SOAP-based Web services
that are finally beginning to make their appearance.
Hastings' Air Fare Quote Search is implemented in Apache Axis and
searches some airline Web sites in real time to find the best available
flight prices for a given itinerary (see Resources). It aggregates and returns the results, sorted by price. The WSDL is at http://wavendon.dsdata.co.uk:8080/axis/services/SBGGetAirFareQuote?wsdl. It defines two operations:
getAirlines. The former is used to execute the price search and takes 4 parameters: two W3C XML Schema Language Data Types (WXSDT)
dateTime values giving the approximate start of the departure and end of the return flights and two WXSDT
values giving the three-letter airport codes between which the travel
is to take place. In interactive Python, we tried the following code:
The examples in the ZSI manual also show the use of a
typesmodule keyword parameter to the
ServiceProxy initializer but doesn't really explain this parameter properly, so we ignored it.
When dates are a real struggle
We need two date/time objects for the service invocation, and the ZSI manual says that "SOAP dates and times are Python time tuples in UTC (GMT), as documented in the Python time module." We tried the following code to see what it would cost to get us to the XML 2003 conference in Philadelphia:
After a lot of vain experimentation (including with ZSI's
class), poring over the documentation, and even some Google searches on
the topic we couldn't figure how to get ZSI to pass a date/time as a
parameter without writing a special class for date/time objects using
gDateTime class as a type code. This seems an amazing hurdle to make a programmer jump over for such a common data type.