SOAP views with on-demand WSDL generation

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# soaplib_handler.py

from soaplib.wsgi_soap import SimpleWSGISoapApp
from soaplib.service import soapmethod
from soaplib.serializers import primitive as soap_types

from django.http import HttpResponse


class DjangoSoapApp(SimpleWSGISoapApp):

    def __call__(self, request):
        django_response = HttpResponse()
        def start_response(status, headers):
            status, reason = status.split(' ', 1)
            django_response.status_code = int(status)
            for header, value in headers:
                django_response[header] = value
        response = super(SimpleWSGISoapApp, self).__call__(request.META, start_response)
        django_response.content = "\n".join(response)

        return django_response


# views.py - sample view

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()


# urls.py

urlpatterns = patterns(
    '',
    (r'^hello_world/', 'foo.views.hello_world_service'),
    (r'^hello_world/service.wsdl', 'foo.views.hello_world_service'),
)

More like this

  1. Automatically expose soaplib methods in WSDL by AndrewIngram 4 years, 3 months ago
  2. SOAP web service with soaplib 0.9+ by wRAR 2 years, 7 months ago
  3. SOAP web service with soaplib 2.0 by treyh 1 year, 4 months ago
  4. django soaplib test client by erny 4 years, 1 month ago
  5. soaplib service integration 2 by erny 4 years, 1 month ago

Comments

adamlofts (on August 15, 2008):

This is a great example. Thanks!

#

csar (on August 15, 2008):

This doesn't work for me because of problems with wsgi.input - have you actually successfully run this? The server just hangs for me trying to read the request from the client. I really wish it would work cause it's such a simple way of structuring this and soaplib looked pretty nice.

#

adamlofts (on August 20, 2008):

I've just started to use this (it works). I have 2 comments:

  1. When you use super() you usually pass the class you are in (not the base class).

  2. To automatically follow Django model relationships I have written a little SoapDjangoArray type; which will follow a reverse foreign key or m2m relationship:

`` class SoapDjangoArray(soap_types.Array):

def to_xml(self, values, name='retval'):
    return soap_types.Array.to_xml(self, values.all(), name)``

#

jsomara (on September 23, 2008):

If you are having a problem with wsgi input, you may want to ensure your webserver is correctly serving WSGI. If you're using apache, you can follow the guide here to set up mod_wsgi: http://code.google.com/p/modwsgi/wiki/IntegrationWithDjango

I had a problem with it hanging as well, but I didn't have mod_wsgi set up correctly. This fixed the issue.

I'm having another issue though, from inside soaplib if I try to 'say_hello': File "/usr/lib/python2.5/site-packages/soaplib/soap.py", line 129, in from_soap if len(body.getchildren()): AttributeError: 'NoneType' object has no attribute 'getchildren'

#

jsomara (on September 23, 2008):

In reference to my last post : this was a user error. I had set up my client as http://localhost:8000/hello_world/service.wsdl instead of http://localhost:8000/hello_world/. Works as intended now.

#

erratic (on January 28, 2009):

You guys are so close!

Ok, so the way I see it is that manage.py (calling manage.py runserver) is setup by default to execute the command (in /usr/lib/python/site-packages/django/core/management/commands) depending on your install runserver.py which seems to me is written with the RESTful pattern in mind. Here is a tutorial that describes how to write a custom command:

http://oebfare.com/blog/2008/nov/03/writing-custom-management-command/

Note that this tutorial demonstrates some interesting ways to use the WSGIServer provided by CherryPy.

Seeing as how we're working with SOAP, it would stand to reason to follow this pattern by implementing a new command and going from there. Could even go so far as to implement a command that supports both the CherryPy WSGI and the soaplib WSGI.

Personally I intend to write my own which initially I only care to have support for the soaplib wsgi but also the ability to allow each SOAP project app its ability to have a sudo-static instance or an instance of an object that remains intact so long as manage.py runsoapserver is running. Since this is the server instance.

Something I haven't thought of yet is whether or not the Django.core.handler.wsgihandler will suffice for use with the soaplib wsgi server. it would stand to reason that since I need to get a "sudo-static" instance of an object that remains as such so long as the WSGI server is running that I'll need to get that object to the appropriate views somehow. Not to mention the handler's filename is "wsgi.py" which kinda pushes anything I might want to write that's "wsgi" out of the way assuming I can't do that, any thoughts or suggestions to this approach I've come up with would be awesome!

Since requests are handled this way, "sudo-static" object instances would be pretty easy to conceal from views that they don't belong to. The idea being, the server gets a request, decides what app is being called on, then passes the instance that belongs to it. Some uses for this would be a way to have something like for example a thread pool that I can have control over via a SOAP API... something that runs while I'm away :)

... again any thoughts are welcome

#

emilianoheyns (on February 12, 2009):

@csar: I'm having the same problem. Do you have a solution yet?

#

emilianoheyns (on February 12, 2009):

Got it: change soaplib_handler into:

soaplib_handler.py

from soaplib.wsgi_soap import SimpleWSGISoapApp from soaplib.service import soapmethod from soaplib.serializers import primitive as soap_types import StringIO

from django.http import HttpResponse

class DumbStringIO(StringIO.StringIO): def read(self, n): return self.getvalue()

class DjangoSoapApp(SimpleWSGISoapApp):

def __call__(self, request):

    django_response = HttpResponse()
    def start_response(status, headers):
        status, reason = status.split(' ', 1)
        django_response.status_code = int(status)
        for header, value in headers:
            django_response[header] = value

    environ = request.META.copy()
    body = ''.join(['%s=%s' % v for v in request.POST.items()])
    environ['CONTENT_LENGTH'] = len(body)
    environ['wsgi.input'] = DumbStringIO(body)
    environ['wsgi.multithread'] = False

    response = super(DjangoSoapApp, self).__call__(environ, start_response)

    django_response.content = "\n".join(response)

    return django_response

#

zdmytriv (on June 18, 2009):

It also hangs for me also,

emilianoheyns's patch works fine.

Thanks

#

lid (on January 7, 2010):

The snippet works very well, the only problem I have is that the reply has no namespace defined :S

#

harmv (on January 29, 2010):

There is a bug in soaplib v8.1 The generated wsdl contains an error.

see: http://github.com/jkp/soaplib/issues/#issue/12

soapui & axis clients don't accept this wsdl

#

inuwashi (on July 9, 2010):

Just FYI the WSDL issue in soaplib v0.8.1 is fixed in the trunk so emilianoheyns version of soaplib_handler works like a charm.

#

defrex (on July 9, 2010):

Looks like optio got purchased, and the link no longer works. You can still get soaplib here though: http://github.com/jkp/soaplib

#

aronchi (on August 25, 2010):

http://github.com/jkp/soaplib is not working now.

I tried http://github.com/arskom/soaplib alpha but it's not working with this code.

Where can I find a correct version of soaplib without that bug?

#

wRAR (on September 28, 2010):

This version is for soaplib 0.9+

#

jonasvp (on November 16, 2010):

emilianoheyns patch saved me... one hint: instead of

body = ''.join(['%s=%s' % v for v in request.POST.items()])

you can simply use

body = request.raw_post_data

#

ealekseev (on December 23, 2010):

I try to use this snippet, but get things like this:

>>> from soaplib.client import make_service_client

>>> from ws.hello.views import HelloWorldService

>>> client = make_service_client('http://localhost:6677/hello_world/', HelloWorldService())

>>> client.say_hello('foo',2)

Traceback (most recent call last): File "\<stdin>", line 1, in \<module> File "/opt/portal/python/lib/python2.7/site-packages/soaplib-0.8.1-py2.7.egg/soaplib/client.py", line 173, in call raise Exception(ex) Exception: 403 FORBIDDEN localhost 6677 /hello_world/

>>> client.server.say_hello('foo',2)

['Hello, foo', 'Hello, foo']

I use apache 2.2.16 + mod_wsgi 3.3, python 2.7.1

Any suggestions why client.say_hello('foo',2) is not working?

#

johngar (on January 7, 2011):

ealekseev I also got 403 forbidden.

I fixed it by turning off the CSRF middleware in the Django settings file.

#

Sharpek (on May 9, 2011):

Hi,

To avoid CSRF Error just add:

@csrf_exempt class HelloWorldService(DjangoSoapApp):

#

hbansal (on November 2, 2011):

soapui is throwing

[HTML_REMOVED]say_helloFault[HTML_REMOVED] [HTML_REMOVED]'say_hello'[HTML_REMOVED] [HTML_REMOVED][HTML_REMOVED] [HTML_REMOVED]

whenever I try to invoke say_hello service, however it works well with suds client.

#

Cross20ALLISON (on December 30, 2011):

If you are willing to buy a house, you would have to receive the credit loans. Furthermore, my sister usually uses a term loan, which seems to be the most useful.

#

miltonlab (on June 12, 2012):

@csrf_exempt really work at soaplib 0.8.1 it work too

#

JeffSilverman (on June 22, 2012):

I have tried to get this snippet to work to no avail. Coded as is. I get a 405 from the web server. What I have left out?

#

JeffSilverman (on June 22, 2012):

In the disection of the 405, the message indiates that the GET is not allowed, but POST is.

#

(Forgotten your password?)