Home

Who are we

Articles

SOAP - A Quick Intro to Webservices

XML-RPC - A Five-Minute Tutorial

Installing Apache2 and mod_perl (Windows XP)

Links

Untitled Document

A SOAP RPC Server and Client in Python

Let's move on to setting up a service in Python and try accessing that from Perl. The package we will be using for this is SOAPpy. You will probably have to install the relevant packages PyXML, fpconst and SOAPpy before being able to run these examples, since the default python installations don't ship with them. Detailed instruction on how to install them can be found here on the very cool Dive Into Python web site by Mark Pilgrim. (Please note that the fpconst package has been moved from the location given in Dive Into Python, so please use the link I provided above.)

dateInfoServer in Python

Once the packages are installed we can try the server code:

 
dateInfoServer.py
 
#! /usr/bin/python
 
from SOAPpy import SOAPServer
import sys, time
 
class Date:
    def dateInfo(self, option) :
        tm = time.localtime()
        year = tm.tm_year
        month = tm.tm_mon
        day = tm.tm_mday
        hour = tm.tm_hour
        min = tm.tm_min
        sec = tm.tm_sec
        
        if (option == "date"):
            return ["%02d/%02d/%04d" % (month, day, year)]
        elif (option == "time"):
            return ["%02d:%02d:%02d" % (hour, min, sec)]
        elif (option == "all"):
            return ["%02d/%02d/%04d" % (month, day, year),
                "%02d:%02d:%02d" % (hour, min, sec)]
        else:
            return "Error - unrecognized option"
        
server = SOAPServer(("localhost", 9000))
server.registerObject(Date(), "urn:/Date")
server.serve_forever()

SOAPServer() sets up the server at the given address and port. registerObject, as the name indicates, registers the Date() object with the name space of the same name. And finally serve_forever() ... well, lets the server run until it gets killed.

Now, let's try accessing it with our perl client. I hope it worked.

I want to take a quick break here and point out the nice debugging feature of SOAPpy. If we add the lines

 
server.config.dumpSOAPOut = 1
server.config.dumpSOAPIn  = 1

we get a dump of the soap messages sent back and forth.

The dateInfoClient

Python makes nice, compact code. And sometimes it makes even nicer code. This is one of these nicer times:

 
dateInfoClient.py
 
#! /usr/bin/python
 
import sys
from SOAPpy import SOAPProxy
 
option = sys.argv[1]
 
serverUrl='http://localhost:9000'
namespace='urn:/Date'
server = SOAPProxy(serverUrl, namespace)
response = server.dateInfo(option)
 
# read out the response
if (response == None):
    print "Call returned error."
    sys.exit(1)
    
if (option == "date"):
    print "Current server date is " + response[0]
elif (option == "time"):
    print "Current server time is " + response[0]
elif (option == "all"):
    print "Currently server date is " + response[0]
    print "Currently server time is " + response[1]

I think the client doesn't require explanation. Setting the name space is probably the most tricky of these operations. Try it and enjoy.

Interoperability between the Perl and Python SOAP Implementations

To come back to the point of interoperability you should find that the python client works just fine with the perl server. However, remember the point about the SOAPAction handler on the perl server. If we comment out or delete the line ->on_action(sub{}) , i.e. remove the empty action handler, this will happen:

 
dateInfoClient.py all
Traceback (most recent call last):
   ...
response = server.dateInfo(option)
   ...
SOAPpy.Types.faultType: <Fault SOAP-ENV:Client: SOAPAction 
shall match 'uri#method' if present(got 'dateInfo', expected 
'urn:/Date#dateInfo'

These is an example of the common annoyances with interoperability. The best way to debug these, besides searching for the error message online, is to look at the SOAP message. In most cases like in this one, there are subtle differences between the implementations. To illustrate this here is a look at the html header sent by the perl client:

 
Content-Type: text/xml; charset=utf-8
SOAPAction: "urn:/Date#dateInfo"

<?xml version="1.0" encoding="UTF-8"?><SOAPEnv..>

Do you see the SOAPAction instructions?

But what if we can't fix the server because we e.g. don't have control over it. Simple - we just need to set the SOAP action in the python client. This is done when invoking the SOAP proxy (the third argument in the constructor defines the SOAP action):

 
server = SOAPProxy(serverUrl, namespace, "urn:/Date#dateInfo")

And as we see, it works again.

Previous: A SOAP RPC Server and Client in Perl