So I’ve been working on creating web services in Python and particualrly in Django, and I’ve got to say – it’s a minefield.

Not only is there a plethora of libraries to create SOAP-based services, but those libraries they are dependent on are out of date, not-supported anymore or insanely difficult to install on a windows-based machine (I know, I know!)

To cap it all off, the recommended ZSI Infrastructure project, which is supposed to be the be-all and end-all of python web services libraries has documentation that is completely out of date or incomplete, meaning it’s an afternoon of guess-work and googling to find any answers (and even then it’s not at all clear).

I’ve found a solution now (after many days of frustrating experimentation) which is really usefull and plays nice with Django, particularly it was this snippet which produced the ideal solution, and combined with SOAPpy makes it easy to test. The following guide will hopefully help others get started quickly butis by no means a definitive guide!

First, get the right libraries – I recommend Soaplib and SOAPPy, you’ll also need a compiled, working copy of PyXML installed (good luck! – You may want to get MinGW if you’re on windows).

Soaplib’s documentation is concise, with some very clear examples to get you up and running really quickly, what’s particularly cool about soaplib is it’s abaility to automatically generate WSDL service descriptions.

The reason I think WSDL generation is so important is because it makes it so easy to consume the service – for example, Asp.Net has excellent web services integration – and consuming a web service is as simple as two clicks with full object generation all done dynamically, lovely.

Finding something that elegant in the python libraries was a bit trickier – most of the functions I found would only consume a WSDL and it’s methods if the appropriate proxy objects were already defined… what a pain…

However, SOAPpy has a nice and simple SOAPProxy object which removes the need for stub objects and almost matches the elegance that ASP.Net has to work with your new service.

Onto some code, here’s a simple example on how to set up your django web service (lifted straight from chewies sample):

from soaplib_handler import DjangoSoapApp, soapmethod, soap_types

class HelloWorldService(DjangoSoapApp):

    __tns__ = 'http://my.namespace.org/soap/'

    @soapmethod(soap_types.String, soap_types.Integer, _returns=soap_types.Array(soap_types.String))
    def say_hello(self, name, times):
        results = []
        for i in range(0, times):
            results.append('Hello, %s'%name)
        return results

hello_world_service = HelloWorldService()

The line worth noting are the @soapmethod descriptor, this is where you describe the inputs and outputs of your service method – it’s pretty straight forward.

For something a little more complex, e.g., let’s say we wanted to syndicate a blog post we’d need to be able to turn our django model query into something that plays nicely with SOAP, since we need to standardise the types used to store the data we can’t just throw the object around like we would normally.

Instead, we define a class that represents our output, and – although tedious – translate our model data into variables defined in the class, this allows us to syndicate more conmplex data structures, we do this using the ClassSerializer object:

from soaplib.serializers.clazz import ClassSerializer
from soaplib.serializers.primitive import String, Integer

class SoapStory(ClassSerializer):
    class types:
        title = String
        strap = String
        url = String
        id = Integer

As you can see, it’s pretty self explanatory setting up the data structure to use that will be sent back in our SOAP response, we tell the view to pass the data in the @soapmethod descriptor, so now we can use the above to create a more complex example:

from soaplib_handler import DjangoSoapApp, soapmethod, soap_types

from soaplib.serializers.clazz import ClassSerializer
from soaplib.serializers.primitive import String, Integer

class SoapStory(ClassSerializer):
    class types:
        title = String
        strap = String
        url = String
        id = Integer

class BlogService(DjangoSoapApp):

    __tns__ = 'http://my.namespace.org/soap/'

    @soapmethod(soap_types.Integer, _returns=SoapStory)
    def get_story(self, id):
        story = post.objects.get(id=id)

        ret = SoapStory()
        if story:
            ret.title = story.title
            ret.strap = story.subheading
            ret.url = story.get_absolute_url()
            ret.id = story.id

    return ret

blog_service = BlogService()

As youc an see, we’ve used our SoapStory object as the return value and from the soaplib.serializers.primitive namespace we can pull in the basic data types to use when serializing our data. Just a note: it also has an Array type which is great if you want to syndicate lists of data, and any array object can hold a ClassSerializer object, so you can create complex, nested lists.

You will need to register the views with your urls.py, the example given in chewie’s snippet is fine for this, just remember to rename hello_world_service to whatever your class is called.

If you browse to the new services.wsdl with your browser you’ll see the XML schema that describes your new service!

Now, just to make things a bit clearer, here’s a simple & quick way to test your service using SOAPPy and it’s SOAPProxy object:

>>> from SOAPpy import SOAPProxy
>>>
>>> url = 'http://localhost:8000/blog_service/service.wsdl'
>>>
>>> proxy = SOAPProxy(url)
>>> results = proxy.get_story(id=1)
>>> print results

if you want to get a list of methods and types in the service, you can just call the proxy.__dict__() to get a list.

As I said, there are many libraries for SOAP based web-services for Python, some better than others, but in order to set up a simple web-service, the libraries mentioned above are in my opinion the best ones for quick deployment (and decent documentation).