Utilizzare tipi complessi, WSDL e conclusioni
difficile
Passaggio di binari
Il protocollo http non prevede lo scambio di valori binari. Qualsiasi cosa venga trasmessa deve quindi essere trasformata con una codifica chiamata Base64 che trasforma un flusso binario in un flusso ascii. Fortunatamente il passaggio di dati binari viene gestito automaticamente attraverso il tipo Attachment.
L'oggetto attachment è dotato di una serie di metodi appositi per la gestione di file.
Vediamo due esempi dalladocumentazione
class DocumentArchiver(SimpleWSGISoapApp):
@soapmethod(Attachment,_returns=String)
def archive_document(self,document):
'''
This method accepts an Attachment object, and returns the filename of the
archived file
'''
fd,fname = mkstemp()
os.close(fd)
document.fileName = fname
document.save_to_file()
return fname
@soapmethod(String,_returns=Attachment)
def get_archived_document(self,file_path):
'''
This method loads a document from the specified file path
and returns it. If the path isn't found, an exception is
raised.
'''
if not os.path.exists(file_path):
raise Exception("File [%s] not found"%file_path)
document = Attachment(fileName=file_path)
# the service automatically loads the data from the file.
# alternatively, The data could be manually loaded into memory
# and loaded into the Attachment like:
# document = Attachment(data=data_from_file)
return document
Questo oggetto contiene due metodi:
Il primo "archive_document" prende in input un file, lo salva in una cartella temporanea e restituisce il nome del file.
Il secondo "get_archived_document" prende in input il nome di un file e restituisce il file.
Il client può sfruttare il server in questo modo:
# client è la nostra istanza remotefilename=client.archive_document(Attachment(fileName="mydata")
mydata è il nome del mio file locale e remotefilename è il nome del file sul sistema remoto.
Posso anche passare al costruttore direttamente una stringa di dati binari.
remotefilename=client.archive_document(Attachment(data=open("binaryfile").read()
Posso recuperare il mio file con
myfile=client.get_archived_document(remotefilename)
# myfile è un oggetto di tipo Attachment
myfile.save_to_file("mydata"
Utilizzare dei tipi composti
E' possibile definire dei tipi composti. Per farlo è necessario che la nostra classe estenda ClassSerializer (from soaplib.serializers.clazz) e definisca una sottoclasse di nome types con un elenco di attributi (semplici o, a loro volta, composti).
Ad esempio:
class Permission(ClassSerializer): class types: application = String feature = String class User(ClassSerializer): class types: userid = Integer username = String firstname = String lastname = String permissions = Array(Permission)
Questi nuovi tipi potranno essere usati nei nostri decoratori soapmethod:
@soapmethod(User)
o
@soapmethod(_returns=Array(User))
Queste classi speciali funzionano come classi normali:
u=User() u.username="Pippo" u.userid=3
Gli attributi non inizializzati saranno però valorizzati None.
Generare WSDL
I wsdl sono dei file xml che contengono la descrizione dell'oggetto: i metodi esposti, la quantità e il tipo degli argomenti e dei valori di ritorno. Tramite questi file su Eclipse, utilizzando Java ad esempio, è possibile farsi costruire automaticamente la classe client.
Soaplib dispone di due modi di generare il wsdl: il primo direttamente dal server aggiungendo "wsdl" all'indirizzo della nostra risorsa. Tornando al nostro primo esempio:
>>> client = make_service_client('http://localhost:7789/',HelloWorldService())
>>> print client.say_hello("Dave",5)
Visitando l'indirizzo http://localhost:7789/wsdl ci verrà restituito il file wsdl.
Il secondo modo per ottenere il wsdl e tramite la funzione
client.server.wsdl('')
In questo modo il wsdl viene generato lato client.
Conclusioni
Direi che abbiamo affrontato tutti i punti relativi all'interfacciamento di un applicazione python tramite web service.
- come usare un web server wsgi (in questo caso cherrypy)
- come scrivere un`interfaccia web (a basso livello con WSGI)
- come esporre degli oggetti tramite il protocollo soap (usando soaplib)
Approfondimenti
Per approfondire l'argomento dei web service può essere interessante esplorare altri tipi di web service, ad esempio xmlrpc (librerie xmlrpc e pyro) o altre implementazioni di soap per python (suds, zsi, twisted ).
