Python SOAP Tutorial - Creating a WEB Service with ZSI
Translated from the article in German ...
Python SOAP Tutorial Creating a WEB Service with ZSI Richard Mutschler Email: Mutschler.Richard@web.de 10. Februar 2007
Table of Contents
1 Foreword 3 1.1 Lizens 3 2 Einf?uhrung 3 3 Einfache Datentypen: Ein rpc/literal MatheService 4 3.1 Die MatheService WSDL 4 3.2 Der Python ZSI Server f?ur den MatheService 5 3.2.1 Methodenstubs aus der WSDL generieren 5 3.2.2 Implementation des MatheService Web- Servers 6 3.2.3 Die Service Implementation einf?ugen 7 3.3 Der Python ZSI Client f?ur den MatheService 10 4 Komplexe Datentypen 12 4.1 Erweitern der WSDL mit Eclipse 12 4.2 Den Erweiterten Server erstellen 16 4.3 Der erweiterte Client 20 5 Deutsche Zusammenfassung des ZSI user manual 22 5.1 ?Ubersicht 22 5.1.1 SOAP Bindings 22 5.1.2 Python Werkzeuge 22 5.2 Von der WSDL zum Python Code 22 5.2.1 wsdl2py - Die Grundlagen der Codeerstellung 23 5.2.2 Typecode Erweiterungen 24 6 Links 25 Index of Diagrams 1 Workspace in Eclipse 12 2 Design View of the MatheServicewsdl 13 3 Design View with new Operation 13 4 Design View with new Operation and assigned elements 13 5 Element ModuloRequest 14 6 Complex Data Type 14
Foreword
Although Web Services an increasingly gr?oere spread reasons, the production from clients and servers are nowhere as simple as at many places promised. This is probably not least because little easy on the theme Einf?uhrungen exist. Just englischsprachige ?auerst instructions are rare. This is the Step Tutorial four step entry into the subject of Web Services f?ur Anf?anger (like me) easier. The Python Implementation is being used.
Licence
Copyright c 2007 Richard Mutschler. All rights reserved.
Sources copied from other authors are labeled with a copyright note. Redistribution and use in source (LYX, LATEX) and 'compiled' forms (SGML, HTML, PDF, Post- Script, RTF and so forth) with or without modification, are permitted provided that the following conditions are met:
- . Redistributions of source code (LYX, LATEX) must retain the above copyright notice, this list of conditions and the following disclaimer as the first lines of this file unmodified.
- . Redistributions in compiled form (transformed to other DTDs, converted to PDF, PostScript, RTF and other formats) must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
THIS DOCUMENTATION IS PROVIDED 'AS IS' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANYWAY OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
Einf?uhrung
It is in this tutorial from a certain Grundkentnis in Python. Some basic concepts of WSDL, SOAP and HTTP servers are beil?au�g presented. It does not mention n?aher, since the network is a lot of information dar?uber verf?ugbar. With this software was to prepare this Tutorials worked
- Python 2.4
- PyXML 0.8.3
- ZSI 2.0 rc3
- soapUI 1.6
- Eclipse 3.2
- PyDev for Eclipse 1.2.5
- Web Standard Tools (WST) for Eclipse 1.5.2
The point of departure shown here four example, a WSDL file. A major collection of WSDL files four further projects unfounded http://www.xmethods.com. under: A major m?oglichst Interoperabilit?at gew?ahrleisten to be here only Web Service 1 battery WSDL files in rpc/literal and document/literal Style.
Simple Datatypes: An RPC/literal MatheService
A simple example, which initially implemented only offering a function, which is a double as receives argument and square the number zur?uckgibt. This example Sp?ater functions to the Modolodivision four expanded. Here are just a simple initially scalar datatypes used a single argument and a R?uckgabewert.
The MathService WSDL
This WSDL forms the interface to MatheService:
<?xml version="1.0"?> <definitions name="MatheService" targetNamespace="http://MyNs:8080/MatheService" xmlns:tns="http://MyNs:8080/MatheService" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns="http://schemas.xmlsoap.org/wsdl/"> <message name="getSquareRequest"> <part name="x" type="xsd:double"/> </message> <message name="getSquareResponse"> <part name="return" type="xsd:double"/> </message> <portType name="SquarePortType"> <operation name="getSquare"> <documentation>the square method </documentation> <input message="tns:getSquareRequest"/> <output message="tns:getSquareResponse"/> </operation> </portType> <binding name="SquareBinding" type="tns:SquarePortType"> <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/> <operation name="getSquare"> <soap:operation soapAction="http://127.0.0.1:8080/MatheService/getSquare"/> <input> <soap:body use="literal" namespace="http://MyNS:8080/MatheService"/> Returns x^2 (x**2, square(x)) for a given float x </documentation> <port name="SquarePort" binding="tns:SquareBinding"> <soap:address location="http://127.0.0.1:8080/MatheService"/> </port> </service> </definitions>
1 Original by Holger Joukl, modified by Richard Mutschler
The Python ZSI Server for the MatheService
The ZSI Web service package is a tool for top-down development of Web-Services. This means that an existing WSDL used to client and server applications. In the context this document describes a Webservice a WSDL file that describes the Service Interface.
Method Stubs Generated from the WSDL
ZSI provides two Python scripts for Verf?ugung which Quellcodeger?uste four Server and Client from the WSDL generated code:
- wsdl2py will be used to the Python Bindings four Service can evolve.
- Wsdl2dispatch creates a Serverger?ust, at the service auszuf?uhren. The processing, with us, so SquareService tabled here.
If ZSI installed, ?o net now top the console and changes in the provided, in which our MatheService.wsdl. Now the two scripts ausgef?uhrt:
- wsdl2py -f MatheService.wsdl
- wsdl2dispatch -f MatheService.wsdl
The option -f speziXis styled the input, so our WSDL file. If a WSDL from the network will be used, for example of http://www.xmethods.com, can here by -u instead of -f the URL. It should not be in the directory three new files be reasons:
- MatheService services.py - Die durch wsdl2py generierten Bindings,
- MatheService services types.py - Durch wsdl2py generierten TypdeXnitionen,
- MatheService services server.py - Das durch wsdl2dispatch generiertes Server Ger?ust.
What to do now? We have the Server skeleton and the Python bindings to use the Service to communicate. What we need now is:
- The main program, the (HTTP-) Server and the Request Handler and
- the Methods, the practices questions.
ZSI includes the module ZSI.ServiceContainer, which the server for us implemented.
Implementation of the MatheService Web-Servers
We create a Python file called MyMatheService.py. I use the Python programming Eclipse with PyDev Plugin, however, there is any free dasWerkzeug seinerWahl. MyMatheService.py is the main program. It is a request Handler, combines the Verf?ugung our Service with the ServiceContainer and starts the HTTP Server.
MyMatheService.py
from ZSI.ServiceContainer import ServiceContainer, SOAPRequestHandler from MatheService_services_server import MatheService import os class MySOAPRequestHandler(SOAPRequestHandler): def do_GET(self): #Return the WSDL file. We expect to get the location from the #invocation URL ("path"). wsdlfile = os.path.join('.', self.path.replace('/', "", 1) + ".wsdl") print ">>>>> using wsdl file", wsdlfile wsdl = open(wsdlfile).read() self.send_xml(wsdl) # Copied from ZSI.ServiceContainer, extended to instantiate with a custom # request handler def AsServer(port=80, services=(), RequestHandlerClass=SOAPRequestHandler): address = ('127.0.0.1', port) sc = ServiceContainer(address, RequestHandlerClass=RequestHandlerClass) for service in services: path = service.getPost() sc.setNode(service, path) sc.serve_forever() AsServer(port=8080, services=[MatheService()], RequestHandlerClass=MySOAPRequestHandler)
W?are n?otig it not been his own Request Handler to implement MySOAPRequestHandler, both Python ZSI Clients, which the ServiceProxy class and MS Visual Basic SOAP Clients, expect a HTTP GET, the WSDL file ?ubermittelt. This is now a widespread behavior. This was the AsServer(..) function will be extended to his own Request handler. We k?onnen Service now test. To test Web Services do I use the Tool SOAPUI. SOAPUI generiert SOAP messages from a WSDL and sends it to the WSDL specified Server.
SOAPUI Request
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:mat="http://MyNS:8080/MatheService"> <soapenv:Body> <mat :getSquare> <x>6</x> </mat :getSquare> </soapenv:Body> </soapenv:Envelope>
SOAPUI Response
<SOAP-ENV:Envelope xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ZSI="http://www.zolera.com/schemas/ZSI/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns: xsi="http://www.w3.org/2001/XMLSchemainstance"> <SOAP-ENV:Header/> <SOAP-ENV:Body xmlns:ns1="http://MyNS:8080/MatheService"> <ns1:getSquareResponse> <return xsi:nil="1"/> </ns1:getSquareResponse> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
The server because we have no function yet wrote that request, we as a result : return xsi:nil=1. That was so far is also expected. We see in particular, however, that the server l?auft and our request receives. To get meaningful results we must implement the getSquare function.
The Service Implementation Einflugen
The only thing we do now m?ussen, is the implementation of the services in the by wsdl2dispatch produced Serverger?ust einzuf?ugen. The following steps are necessary:
- Forwarding the request of the correct method,
- the method the parameters of the SOAP- request ?ubergeben,
- the result of the method in the SOAP- response letter.
We first ?o nen MatheService_services_server.py file:
################################################## # MatheService_services_server.py # Generated by ZSI.generate.wsdl2dispatch.DelAuthServiceModuleWriter # ################################################## from MatheService_services import * from ZSI.ServiceContainer import ServiceSOAPBinding class MatheService(ServiceSOAPBinding): soapAction = {} root = {} _wsdl = """...""" def __init__(self, post='/MatheService', **kw): ServiceSOAPBinding.__init__(self, post) def soap_getSquare(self, ps): self.request = ps.Parse(getSquareRequest.typecode) x = self.request._x Response = getSquareResponse() Response._result=self.getSquare(x) return Response soapAction['http://MyNs:8080/MatheService/getSquare'] = 'soap_getSquare' root[(getSquareRequest.typecode.nspname,getSquareRequest.typecode.pname)] = 'soap_getSquare'
We f?ugen now the function getSquare added, the ausgef?uhrt will be at the square a number to compute
def getSquare(self, x): return x**2
Now we function ver?andern soap getSquare(self, ps):
def soap_getSquare(self, ps): self.request = ps.Parse(getSquareRequest.typecode) x = self.request._x Response = getSquareResponse() Response._result=self.getSquare(x) return Response
In line 2 args = ps.Parse(getSquareRequest) ways of the variable we args an array of the request. The class getSquareRequest is in the file MatheService_services.py below:
. . . class getSquareRequest: def __init__(self): self._x = None return . . . class getSquareResponse: def __init__(self): self._return = None return . . .
In line 3 response=getSquareResponse(), we reject the Variable Response the type getSquareResponse().
In line 4 is now our getSquare method is called. The parameter is the x value of the inquiry (the '_' is important!!!) method. The result, we then the Variable return our response variable.
At the end we give the with a value gef?ullte Response Variable zur?uck. We are testing our server now come back with SOAPUI:
SOAPUI Request
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:mat="http://MyNS:8080/MatheService"> <soapenv:Body> <mat :getSquare> <x>6</x> </mat :getSquare> </soapenv:Body> </soapenv:Envelope>
SOAPUI Response
<pre> <SOAP-ENV:Envelope xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ZSI="http://www.zolera.com/schemas/ZSI/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns: xsi="http://www.w3.org/2001/XMLSchemainstance"> <SOAP-ENV:Header/> <SOAP-ENV:Body xmlns:ns1="http://MyNS:8080/MatheService"> <ns1:getSquareResponse> <return>36.000000</return> </ns1:getSquareResponse> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
We add the function getSquare added, which should be processed at the square a number of calculated:
Congratulations, our Server works!
The Python ZSI Client for MatheService
At the Client to implement, we create a new Python file, in this example MyMathServiceClient.py:
MyMatheServiceClient.py
from MatheService_services import * from MatheService_services_types import * import sys from optparse import OptionParser parser= OptionParser() parser.add_option("-s", "--square", dest="square", type="string", help="A number calculate Square ") parser.add_option("-a", "--arg1", dest="arg1", type="string", help="The first Modulodivision parameter ") parser.add_option("-b", "--arg2", dest="arg2", type="string", help="The second Modulodivision parameter") (options, args)=parser.parse_args() loc = MatheServiceLocator() proxy = loc.getMathePortType(tracefile = sys.stdout) if options.square: response= proxy.getSquare((float)(options.square)) print "The square of ", options.square, "is: ", response elif options.Zahl1 and options.Zahl2: response = proxy.getModulo((int)(options.arg1),(int)(options.srg2)) print "The result of the modulodivision of ", options.Zahl1, "and", options.Zahl2, "is", response
We recognize quickly that the client pretty simple. The relevant lines of code will now be explained :
- Line 1: The wsdl2py created bindings are imported.
- Line 14: an instance of Locator class is created. The Locator MatheService_services.py class is defined. Of the locate represents the Bindings at the given Web Service and the Port class, which is used to the Remote operations involve Web Services. In addition, several classes defined message to the SOAP, XML Schema datatypes locations. The name of this class depending, of course the name of the WSDL defined Services. This means that if any other WSDL used the name changes also. You will find the class of wsdl2py generated _services.py file is quite simple (it is the first class, who in the file is always on and ends ServiceLocator).
- Line 15: the variables proxy, the port of Locator- class assigned. Through this port will be the operations of the Web Services. The specified parameters tracefile = sys.stdout there for debugging the SOAP messages on the standard output.
- Line 22: as well as the Server we need the instance of class, the type of data from the SOAP message represents.
- Line 23: similar to the server we fill our request with a value. Note: In Eclipse, the possible variables that are in the request can be set by the code (Strg Space) displayed.
- Line 24: here is now the Operation getSquare called and the result of the Variable response.
The following Listing shows the console output from running our Client:
Running MyMatheServiceClient.py
$ python MyMatheServiceClient.py -s 3.3 ______________________________________________ XXX <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:mat="http://MyNS:8080/MatheService"> <soapenv:Body> <mat :getSquare> <x>6</x> </mat :getSquare> </soapenv:Body> </soapenv:Envelope>
Congratulations, our client also works!
3.2.3 Die Service Implementation einf?ugen
3.3 Der Python ZSI Client f?ur den MatheService
4 Complex Data Types
4.1 Erweitern der WSDL mit Eclipse
4.2 Den Erweiterten Server erstellen
4.3 Der erweiterte Client
5 Deutsche Zusammenfassung des ZSI user manual
5.1 ?Ubersicht
5.1.1 SOAP Bindings
5.1.2 Python Werkzeuge
5.2 Von der WSDL zum Python Code
5.2.1 wsdl2py - Die Grundlagen der Codeerstellung
NCName in AName transformieren:
1. Vorangestellter Unterstrich ' ' Preceded stressed 2. Zeichen, die nicht in dem Zeichensatz(Buchstabe, Zir, ' ') vorkommen, werden durch ' ' ersetzt. Characters that are not in the characterset(, Zir, ' '), occur, ' ' replaced
Attribut Deklarationen:
attrs aname: Attrs aname ist ein Attribut einer TypeCode Instanz. is an attribute of a order instance
Sein Wert ist eine Zeichenkette, die den Attributnamen darstellt, der verwendet wird, um auf ein Dictionary zu verweisen. Dieses enth?alt Daten, welche die Attributdeklaration darstellen.
Die Schl?ussel dieses dictionary sind die (namespace, Name) Tupel. Der Wert jedes Schl?ussels stellt den Wert des Attributes dar.
5.2.2 Typecode Extensions
The option {complexType, -b: the Option {complexType when invoking wsdl2py provides the programr many simplifications to Verf?ugung. This option is tested and the use of the authors recommended.
Low-level Description :
If the Option {complexType set all the attribute generated pyclasses metaclass hinzugef?ugt. The Metaklasse pr?uft the order attributes of pyclass and created a set of Hilfsmethoden f?ur each Element and attribute that in the De �economic of the ComplexType specified. This option f?ugt Wrapper f?ur the handling of the content added, without the generation of ?andern.
Getter/Setter:
A getter and a setters method is f?ur each element of a complex types de�and. These methods will get element ANAME ANAME and set element.
Factory Method:
If an element of complex type himself a complex type, it is for easier handling a factory method creates an instance of the holder class of type zur?uckgibt. The factory method is called 'newANAME'.
Attributes:
Four Python classes are four each element of a complex type properties (properties) creates. These are on the appropriate getter and setter methods of the element illustrated. Namens?uberschneidungen order to avoid these properties 'PNAME',, the first letter of the pname attribute a large type written
fromm ZSI.ServiceContainer import ServiceContainer, SOAPRequestHandler from MatheService_services_server import MatheService import os class MySOAPRequestHandler(SOAPRequestHandler): def do_GET(self): #Return the WSDL file. We expect to get the location from the #invocation URL ("path"). wsdlfile = os.path.join('.', self.path.replace('/', "", 1) + ".wsdl") print ">>>>> using wsdl file", wsdlfile wsdl = open(wsdlfile).read() self.send_xml(wsdl) # Copied from ZSI.ServiceContainer, extended to instantiate with a custom # request handler def AsServer(port=80, services=(), RequestHandlerClass=SOAPRequestHandler): address = ('127.0.0.1', port) sc = ServiceContainer(address, RequestHandlerClass=RequestHandlerClass) for service in services: path = service.getPost() sc.setNode(service, path) sc.serve_forever() AsServer(port=8080, services=[MatheService()], RequestHandlerClass=MySOAPRequestHandler)
6. Links
Here are the Links to download the tools used:
* EntwicklungsIDE Eclipse: http://www.eclipse.org * Zolera SOAP Infrastructure (ZSI) http://pywebsvcs.sourceforge.net/ * Python 2.5 http://www.python.org/download/releases/2.5/ * PyXML http://sourceforge.net/projects/pyxml/ * soapUI 1.5 http://www.soapui.org/