Developer Forums | About Us | Site Map
Search  
HOME > TUTORIALS > SERVER SIDE CODING > PYTHON TUTORIALS > PYTHON SOAP LIBRARIES


Sponsors





Useful Lists

Web Host
site hosted by netplex

Online Manuals

Python SOAP libraries
By Mike Olson and Uche Ogbuji - 2004-09-14 Page:  1 2 3

Putting it all together

After importing the library we set up the proxy object, remote. This object translates method invocations into remote SOAP messages. Its initializer takes the key parameters that govern remote requests: the URI of the server ( known as the "endpoint"), the XML namespace of the request element (this is where SOAP-as-RPC gives lip service to its XML underpinnings), and the SOAPAction header value.

Next we determine the method argument, which in the case of this Web service is simply the language for Haddock's rantings, Swedish ("se") or English (strangely enough, "us" rather than "en").

Finally, we invoke the method of the right name, Curse on the proxy object to make the SOAP call, then we print the results. The following session illustrates the use of the program:


$ python curse.py 
What captain Haddock had to say: "Ectoplasmic Byproduct!"

Our own SOAP server

Implementing a SOAP server in SOAP.py is quite easy. As an example, we shall emulate the field and also implement a trivial service: a program which, given a year and month, prints back a calendar as a string. The server program for this is Listing 2 (calendar-ws.py).

Listing 2: SOAP.py program to implement calendar server


  #!/usr/bin/env python

import sys, calendar

#Import the SOAP.py machinery
from WebServices import SOAP

CAL_NS = "http://uche.ogbuji.net/eg/ws/simple-cal"

class Calendar:
  def getMonth(self, year, month):
    return calendar.month(year, month)

  def getYear(self, year):
    return calendar.calendar(year)


server = SOAP.SOAPServer(("localhost", 8888))
cal = Calendar()
server.registerObject(cal, CAL_NS)

print "Starting server..."
server.serve_forever()

After the requisite imports, we define the namespace (CAL_NS) expected for SOAP request elements to our server. Next we define the class that implements all the methods which are to be exposed as SOAP methods. One can register individual functions as SOAP methods as well, but using the class approach is most flexible, especially if you wish to manage state between invocations. This Calendar class defines one method, getMonth, which uses Python's built-in calendar module to return a monthly calendar in text form, and another method which returns an entire year's calendar.

Then an instance of the SOAP server framework is created, with instructions to listen on port 8888. We must also create an instance of the Calendar class, which is registered to handle SOAP messages in the next line, with the relevant namespace indicated. Finally, we call the serve_forever methods, which doesn't return until the process is terminated.

In order to run the server, open up another command shell and execute python calendar-ws.py. Use ctrl-C to kill the process when you are done.

We could test the server with a client also written with SOAP.py, but that would be too obvious. Let us instead write a client in low-level Python to construct the SOAP response as an XML string and send an HTTP message. This program (testcal.py) is in Listing 3.

Listing 3: A client written using the Python core libraries to access the calendar service


  import sys, httplib

SERVER_ADDR = "127.0.0.1"
SERVER_PORT = 8888
CAL_NS = "http://uche.ogbuji.net/ws/eg/simple-cal"

BODY_TEMPLATE = """<SOAP-ENV:Envelope
  xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
  xmlns:s="http://uche.ogbuji.net/eg/ws/simple-cal"
  xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
  xmlns:xsd="http://www.w3.org/1999/XMLSchema"
  SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
  <SOAP-ENV:Body>

    <s:getMonth>
      <year xsi:type="xsd:integer">%s</year>
      <month xsi:type="xsd:integer">%s</month>
    </s:getMonth>
  </SOAP-ENV:Body>

</SOAP-ENV:Envelope>"""


def GetMonth():
    year = 2001
    month = 12
    body = BODY_TEMPLATE%(year, month)
    blen = len(body)
    requestor = httplib.HTTP(SERVER_ADDR, SERVER_PORT)
    requestor.putrequest("POST", "cal-server")
    requestor.putheader("Host", SERVER_ADDR)
    requestor.putheader("Content-Type", "text/plain; charset="utf-8"")
    requestor.putheader("Content-Length", str(blen))
    requestor.putheader("SOAPAction", "http://uche.ogbuji.net/eg/ws/simple-car")
    requestor.endheaders()
    requestor.send(body)
    (status_code, message, reply_headers) = requestor.getreply()
    reply_body = requestor.getfile().read()

    print "status code:", status_code
    print "status message:", message
    print "HTTP reply body:\n", reply_body


if __name__ == "__main__":
    GetMonth()


The following session illustrates the running of this test.



$ python testcal.py 
status code: 200
status message: OK
HTTP reply body:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" 
xmlns:xsd="http://www.w3.org/1999/XMLSchema" xmlns:SOAP-
ENV="http://schemas.xmlsoap.org/soap/envelope/" 
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance" 
xmlns:SO
AP-ENC="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<getMonthResponse SOAP-ENC:root="1">
<Result xsi:type="xsd:string">    December 2001
Mo Tu We Th Fr Sa Su
                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

</Result>
</getMonthResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

Bytes under scrutiny

One thing useful to note is that you can get details of the actual SOAP messages being exchanged and other key data for debugging and tracing, if you look for the line self.debug = 0 and change the "0" to "1" (this is line 210 in SOAP.py version 0.9.7.) As an example, here is a session with the earlier curses.py program with debugging information turned on:




$ python curse.py 
*** Outgoing HTTP headers **********************************************
POST /scripts/Haddock.exe/soap/IHaddock HTTP/1.0
Host: www.tankebolaget.se
User-agent: SOAP.py 0.9.7 (actzero.com)
Content-type: text/xml; charset="UTF-8"
Content-length: 523
SOAPAction: "urn:HaddockIntf-IHaddock#Curse"
************************************************************************
*** Outgoing SOAP ******************************************************
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" 
xmlns:xsd="http://www.w3.org/1999/XMLSchema" xmlns:SOAP-
ENV="http://schemas.xmlsoap.org/soap/envelope/" 
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance" 
xmlns:SO
AP-ENC="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<ns1:Curse xmlns:ns1="urn:HaddockIntf-IHaddock" SOAP-ENC:root="1">
<LangCode xsi:type="xsd:string">us</LangCode>
</ns1:Curse>
</SOAP-ENV:Body>

</SOAP-ENV:Envelope>
************************************************************************
*** Incoming HTTP headers **********************************************
HTTP/1.? 200 OK
Server: Microsoft-IIS/5.0
Date: Tue, 11 Sep 2001 16:40:19 GMT
Content-Type: text/xml
Content-Length: 528
Content:
************************************************************************
*** Incoming SOAP ******************************************************
<?xml version="1.0" encoding="UTF-8"?><SOAP-ENV:Envelope xmlns:SOAP-
ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/1999/XMLSchema" 
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xml
soap.org/soap/encoding/"><SOAP-ENV:Body><NS1:CurseResponse xmlns:NS1="urn:HaddockIntf-
IHaddock" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><NS1:return 
xsi:type="xsd:string">Anacoluthons!</NS1:return></NS1:CurseRespon
se></SOAP-ENV:Body></SOAP-ENV:Envelope>
************************************************************************
What captain Haddock had to say: "Anacoluthons!"

To compare, you would get this same information in a traditional Python script or program with the following code:




import calendar
return calendar.month(2001, 10)

SOAP.py concentrate

As we've noted, there are some hiccups with interoperability of SOAP.py, but hopefully the debugging data available is of help -- and among the developers who have signed up to keep this project moving along is Mike Olson, co-author of this column. In the next installment of this column we shall look at one of the other Python SOAP implementations.



View Python SOAP libraries Discussion

Page:  1 2 3 Next Page: Resources

First published by IBM developerWorks


Copyright 2004-2024 GrindingGears.com. All rights reserved.
Article copyright and all rights retained by the author.