Python SOAP Tutorial - Creating a WEB Service with ZSI

From PeformIQ Upgrade
Jump to navigation Jump to search

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:

  1. . 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.
  2. . 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 add the function getSquare, which calculates and returns the square a number passed to it as an argument:

    def getSquare(self, x):
        return x**2

Now we add the function soap_setSquare(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

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

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.arg1 and options.arg2:
    response = proxy.getModulo((int)(options.arg1),(int)(options.srg2))
    print "The result of the modulodivision of ", options.arg1, "and", options.arg2, "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
________________________________________ Tue Feb 6 16:48:44 2007  REQUEST:
<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/XMLSchema-instance">
  <SOAP-ENV:Header>
  </SOAP-ENV:Header>
  <SOAP-ENV:Body xmlns:ns1="http://MyNS:8080/MatheService">
    <ns1:getSquare>
      <x>3.300000</x>
    </ns1:getSquare>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>
__________________________________________ Tue Feb 6 16:48:45 2007  RESPONSE:
200
OK
_________________________________
Server:ZSI/1.1BaseHTTP/0.3Python/2.4.4
Date:Tue,06Feb200715:48:45GMT
Content-type:text/xml;charset="utf-8"
Content-Length:484
<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/XMLSchema-instance">
  <SOAP-ENV:Header>
  </SOAP-ENV:Header>
  <SOAP-ENV:Body xmlns:ns1="http://MyNS:8080/MatheService">
    <ns1:getSquareResponse>
      <return>10.890000</return>
    </ns1:getSquareResponse>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>
The square of 3.3 is 10.89


Congratulations, our client also works!

4 Complex Data Types

In the first part of this manual, we have a Service with simple datatypes created. This example is a complex operation datatypes expanded. This we implement an operation which a Modulodivision makes two numbers. As a Parameter ?ubergeben we the Operation two numbers of type integer. Several values in a request to ?ubergeben k?onnen ben?otigen, a type of data folgendermaen looks like:

Complex datatype for the Modulerequest

In the first part of this tutorial, we implemented a Service with simple datatypes. This example demonstrates how a complex operation datatypes is handled. Toa achieve this we implement an operation where the Modulodivision generates two numbers. As a Parameter ?ubergeben we the Operation two numbers of type integer. Several values in a request to ?ubergeben k?onnen ben?otigen, a type of data folgendermaen looks like:

Complex Datatype for ModuleRequest

<xsd:complexType name="ModuloRequest">
<xsd:sequence>
<xsd:element name="Zahl1" type="xsd:int"></xsd:element>
<xsd:element name="Zahl2" type=" xsd:int"></xsd:element>
</xsd:sequence>
</xsd:complexType>

4.1 How to Expand the WSDL with Eclipse

First, in Eclipse a new folder in the project created and the original WSDL imported. In the first part of this manual, we have a rpc/literal encoded WSDL. We are now document/literal encoding.

MatheService Files.gif

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/