Python et les Web Services

Les web service permettent un découplage entre les données et leurs utilisations.

Ainsi un client peut être en python et le server qui distribue le web service en java.

Un peu de vocabulaire

Web Service : typiquement, c’est un programme informatique capable de recevoir/transmettre des données entre des applications et systèmes hétérogènes (oui, wikipedia m’a aidé). Pour faire simple et vulgaire, c’est une application qui peut fonctionner à peu près partout et n’importe comment. Exemple : on peut utiliser un web service comme une bibliothèque partagée via réseau intranet/Internet par des programmes écrits dans différents langages.

SOAP : Protocole RPC (Remote Procedure Call), basé sur XML, utilisé pour appeler et retourner le résultat d’une fonction distante.

WSDL (Web Service Description Language): Format XML servant à décrire un web service. En effet, pour pouvoir utiliser un web service, il nous faut connaître sa structure : le nom des fonctions, les paramètres, etc... C’est à ça que sert la description WSDL.

Il existe comme souvent en python un module qui gère ce genre de problématique: soappy.

son installation

pip install soappy

son utilisation: on va faire un serveur et un client soap

server.py

import SOAPpy

def hello():
    return "Hello World"

def msg(txt):
    return "Your message is %s " % txt

server = SOAPpy.SOAPServer(("localhost", 8085))
server.registerFunction(hello)
server.registerFunction(msg)
server.serve_forever()

client.py

import SOAPpy
server = SOAPpy.SOAPProxy("http://localhost:8085/")
print server.hello()
print server.msg('coucou')

Note

Pour voir les trames transmises et reçues on ajoute

server.config.debug = 1

vous lancez maintenant le serveur puis le client: et voilà tout le monde communique

son installation

python server.py &
python client.py

On peut écrire un client rapide pour é=essayer le serveur (on utilise un message xml directement dans l’appli)

# post xml soap message

import sys, httplib

# a "as lighter as possible" soap message:

SoapMessage= """<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope
   SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
    xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
    xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
    xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:xsd="http://www.w3.org/1999/XMLSchema"
    >
    <SOAP-ENV:Body>
        <getTemp SOAP-ENC:root="1">
           <v1 xsi:type="xsd:int">85500</v1>
           </getTemp>
           </SOAP-ENV:Body>
        </SOAP-ENV:Envelope>
"""

#construct and send the header

webservice = httplib.HTTP("127.0.0.1:8085")
webservice.putrequest("POST", "/")
webservice.putheader("Host", "127.0.0.1:8085")
webservice.putheader("User-Agent", "Python post")
webservice.putheader("Content-type", "text/xml; charset=\"UTF-8\"")
webservice.putheader("Content-length", "%d" % len(SoapMessage))
webservice.putheader("SOAPAction", "\"\"")
webservice.endheaders()
webservice.send(SoapMessage)

# get the response

statuscode, statusmessage, header = webservice.getreply()
print "Response: ", statuscode, statusmessage
print "headers: ", header
res = webservice.getfile().read()
print res

On peut utiliser le module soappy pour faire de l’instrospection de web service

from SOAPpy import WSDL
wsdlFile = 'http://www.xmethods.net/sd/2001/TemperatureService.wsdl'
server = WSDL.Proxy(wsdlFile)
print server.methods.keys()
callInfo = server.methods['getTemp']
print callInfo.inparams
print callInfo.inparams[0].name
print callInfo.inparams[0].type
# on utilise le web service
print server.getTemp('90210')

Note

le module soappy ne permet pas la génération automatique du fichier wsdl, il faut don l’écrire à la main pour le rendre disponible.

exemple de fichier wsdl

<?xml version="1.0"?>
<definitions name="TemperatureService" targetNamespace="http://www.xmethods.net/sd/TemperatureService.wsdl" xmlns:tns="http://www.xmethods.net/sd/TemperatureService.wsdl" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns="http://schemas.xmlsoap.org/wsdl/">
<message name="getTempRequest">
<part name="zipcode" type="xsd:string"/>
</message>
<message name="getTempResponse">
<part name="return" type="xsd:float"/>
</message>
<portType name="TemperaturePortType">
<operation name="getTemp">
<input message="tns:getTempRequest"/>
<output message="tns:getTempResponse"/>
</operation>
</portType>
<binding name="TemperatureBinding" type="tns:TemperaturePortType">
<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="getTemp">
<soap:operation soapAction=""/>
<input>
<soap:body use="encoded" namespace="urn:xmethods-Temperature" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
</input>
<output>
<soap:body use="encoded" namespace="urn:xmethods-Temperature" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
</output>
</operation>
</binding>
<service name="TemperatureService">
<documentation>Returns current temperature in a given U.S. zipcode </documentation>
<port name="TemperaturePort" binding="tns:TemperatureBinding">
<soap:address location="http://services.xmethods.net:80/soap/servlet/rpcrouter"/>
</port>
</service>
</definitions>