Zanurkuj w Pythonie/Introspekcja SOAP z użyciem WSDL
Introspekcja SOAP z użyciem WSDL
edytujPodobnie jak wiele rzeczy w obszarze serwisów sieciowych, WSDL posiada burzliwą historię, pełną politycznych sporów i intryg. Jednak przeskoczymy ten wątek historyczny, ponieważ może wydawać się nudny. Istnieje także trochę innych standardów, które pełnią podobną funkcję, jednak WDSL jest najbardziej popularny, zatem nauczmy się go używać.
Najbardziej fundamentalną rzeczą, na którą nam pozwala WSDL jest odkrywanie dostępnych metod oferowanych przez serwer SOAP.
Przykład 12.8. Odkrywanie dostępnych metod
>>> from SOAPpy import WSDL #(1) >>> wsdlFile = 'http://www.xmethods.net/sd/2001/TemperatureService.wsdl') >>> server = WSDL.Proxy(wsdlFile) #(2) >>> server.methods.keys() #(3) [u'getTemp']
- SOAPpy zawiera parser WSDL. W czasie pisania tego podrozdziału, parser ten określany był jako moduł na wczesnym etapie rozwoju, jednak nie było problemów podczas testowania z parsowanymi plikami WSDL.
- Aby skorzystać z pliku WSDL, ponownie korzystamy z klasy pośredniczącej (ang. proxy), WSDL.Proxy, która przyjmuje pojedynczy argument: plik WSDL. Zauważmy, że w tym przypadku przekazaliśmy adres URL pliku WSDL, który jest przechowywany gdzieś na zdalnym serwerze, ale klasa pośrednicząca równie dobrze sobie z nim radzi jak z lokalną kopią pliku WSDL. Podczas tworzenia 'pośrednika WSDL, plik WSDL zostanie pobrany i sparsowany, więc jeśli wystąpią jakieś błędy w pliku WSDL (lub gdy będziemy mieli problemy z siecią), będziemy o tym wiedzieć natychmiast.
- Klasa pośrednicząca WSDL przechowuje dostępne funkcje w postaci pythonowego słownika, server.methods. Zatem, aby pobrać listę dostępnych metod, wystarczy wywołać metodę keys należącą do słownika.
OK, więc już wiemy, że ten serwer SOAP oferuje jedną metodę: getTemp. Jednak w jaki sposób ją wywołać? Obiekt pośredniczący WSDL może nam także o tym powiedzieć.
Przykład 12.9. Odkrywanie argumentów metody
>>> callInfo = server.methods['getTemp'] #(1) >>> callInfo.inparams #(2) [<SOAPpy.wstools.WSDLTools.ParameterInfo instance at 0x00CF3AD0>] >>> callInfo.inparams[0].name #(3) u'zipcode' >>> callInfo.inparams[0].type #(4) (u'http://www.w3.org/2001/XMLSchema', u'string')
- Słownik server.methods jest wypełniony określoną przez SOAPpy strukturą nazwaną CallInfo. Obiekt CallInfo zawiera informacje na temat jednej określonej funkcji, włączając w to argumenty funkcji.
- Argumenty funkcji są przechowywane w callInfo.inparams, która jest pythonową listą obiektów ParameterInfo, które z kolei zawierają informacje na temat każdego parametru.
- Każdy obiekt ParameterInfo przechowuje atrybut name, który jest nazwą argumentu. Nie trzeba znać nazwy argumentu, aby wywołać funkcje poprzez SOAP, jednak SOAP obsługuje argumenty nazwane w wywołaniach funkcji (podobnie jak Python), a za pomocą WSDL.Proxy będziemy mogli poprawnie obsługiwać nazywane argumenty, które zostają przekazywane do zewnętrznej funkcji (oczywiście, jeśli to włączymy).
- Ponadto każdy parametr ma wyraźnie określony typ, a korzysta tu z typów zdefiniowanych w XML Schema. Widzieliśmy to już wcześniej; przestrzeń nazw "XML Schema" była częścią "formularza umowy", jednak to zignorowaliśmy i nadal możemy to ignorować, ponieważ tutaj do niczego nie jest nam to potrzebne. Parametr zipcode jest łańcuchem znaków i jeśli przekażemy pythonowy łańcuch znaków do obiektu WSDL.Proxy, zostanie on poprawnie zmapowany i wysłany na serwer.
WSDL także nas informuje o zwracanych przez funkcję wartościach.
Przykład 12.10. Odkrywanie zwracanych wartości metody
>>> callInfo.outparams #(1) [<SOAPpy.wstools.WSDLTools.ParameterInfo instance at 0x00CF3AF8>] >>> callInfo.outparams[0].name #(2) u'return' >>> callInfo.outparams[0].type (u'http://www.w3.org/2001/XMLSchema', u'float')
- Uzupełnieniem do argumentów funkcji callInfo.inparams jest callInfo.outparams, który odnosi się do zwracanej wartości. Jest to także lista, ponieważ funkcje wywoływane poprzez SOAP mogą zwracać wiele wartości, podobnie zresztą jak funkcje Pythona.
- Każdy obiekt ParameterInfo zawiera atrybuty name i type. Funkcja ta zwraca pojedynczą wartość nazwaną return, która jest liczbą zmiennoprzecinkową (czyli float)..
Teraz połączmy zdobytą wiedzę i wywołajmy serwis sieciowy SOAP poprzez pośrednika WSDL.
Przykład 12.11. Wywoływanie usługi sieciowej poprzez WSDL.Proxy
>>> from SOAPpy import WSDL >>> wsdlFile = 'http://www.xmethods.net/sd/2001/TemperatureService.wsdl') >>> server = WSDL.Proxy(wsdlFile) #(1) >>> server.getTemp('90210') #(2) 66.0 >>> server.soapproxy.config.dumpSOAPOut = 1 #(3) >>> server.soapproxy.config.dumpSOAPIn = 1 >>> temperature = server.getTemp('90210') *** Outgoing SOAP ****************************************************** <?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> <ns1:getTemp xmlns:ns1="urn:xmethods-Temperature" SOAP-ENC:root="1"> <v1 xsi:type="xsd:string">90210</v1> </ns1:getTemp> </SOAP-ENV:Body> </SOAP-ENV:Envelope> ************************************************************************ *** Incoming SOAP ****************************************************** <?xml version='1.0' encoding='UTF-8'?> <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <SOAP-ENV:Body> <ns1:getTempResponse xmlns:ns1="urn:xmethods-Temperature" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <return xsi:type="xsd:float">66.0</return> </ns1:getTempResponse> </SOAP-ENV:Body> </SOAP-ENV:Envelope> ************************************************************************ >>> temperature 66.0
- Widzimy, że konfiguracja jest prostsza niż wywoływanie serwisu SOAP bezpośrednio, ponieważ plik WSDL zawiera informację zarówno o URL serwisu, jak i o przestrzeni nazw, którą potrzebujemy, aby wywołać serwis. Tworzony obiekt WSDL.Proxy pobiera plik WSDL, parsuje go i konfiguruje obiekt SOAPProxy, który będzie wykorzystywał do wywoływania konkretnego serwisu SOAP.
- Po utworzeniu obiektu WSDL.Proxy, możemy wywoływać funkcje równie prosto jak za pomocą obiektu SOAPProxy. Nie jest to zaskakujące; WSDL.Proxy jest właśnie otoczką (ang. wrapper) dla SOAPProxy z kilkoma dodanymi metodami, a więc składnia wywoływania funkcji jest taka sama.
- Możemy dostać się do obiektu SOAPProxy w WSDL.Proxy za pomocą server.soapproxy. Ta opcja jest przydatna, aby włączyć debugowanie, dlatego też kiedy wywołujemy funkcję poprzez pośrednika WSDL, jego SOAPProxy będzie pokazywał przychodzące i wychodzące przez łącze dokumenty XML.