WSDL im Detail

15.07.2006 von Martin Kuppinger
WSDL, die Web Service Description Language, dient dazu, die Web Services zu beschreiben. Die Dateien können beim Web Service-Designelement von Domino zwar automatisch erzeugt werden, doch ist ein tieferes Verständnis von WSDL für die effiziente Arbeit mit Web Services unverzichtbar.

WSDL ist neben UDDI und SOAP der zentrale Standard für Web Services. Er ist in www.w3c.org/TR/wsdl definiert. Die aktuelle bereits seit 2001 gültige Version ist 1.1.

Mit dem Protokoll werden die Dienste beschrieben, die im Netzwerk angeboten werden. Für jeden Web Service, den man erstellt, muss man auch eine entsprechende Datei erzeugen. WSDL kann bei Lotus Domino automatisch erzeugt und auch importiert werden. Ein Überblick über WSDL ist aber sowohl für das Verständnis der Erstellung von Web Services mit dem entsprechenden Designelement als auch eventuelle Modifikationen an Web Services und den beschreibenden WSDL-Dateien unverzichtbar. Hinzu kommt, dass Lotus Domino nur einen Teil des WSDL-Standards unterstützt und einige Informationen nicht übernommen werden.

Listing 1 zeigt ein Beispiel für einen Web Service, der im Zusammenhang mit dem IBM Workplace in Heft 5/2006 erstellt wurde. Dort wurden einige Aspekte erläutert, wobei der Schwerpunkt auf spezifischen Details lag. Der Artikel geht nun allgemein auf die Grundlagen und Strukturen von WSDL ein und nutzt das gleiche Beispiel.

Grundelemente in WSDL-Dateien

WSDL-Dokumente bestehen aus den folgenden Grundinformationen:

Eingebunden sind diese Informationen in den Tag <wsdl:definitions>. Die Definitionen eines Web Service enthalten zusätzlich die Deklarationen der verwendeten Namensbereiche. Hier wird beispielsweise auf die WSDL-Definitionen, auf SOAP, auf die Encoding-Richtlinien für SOAP und auf andere Informationen verwiesen.

Das Beispiel aus Listing 1

Die Struktur von WSDL wird am einfachsten verständlich, wenn man sich die einzelnen Einträge in einer WSDL-Datei näher betrachtet. Das Listing 1 zeigt eine sehr einfache Datei. Sie beginnt mit

<?xml version="1.0" encoding="UTF-8"?>

Dieser Eintrag verweist auf die XML-Version – in der Regel 1.0 – und den verwendeten Zeichensatz. Anschließend beginnt die eigentliche Beschreibung des Web Service mit

<wsdl:definitions targetNamespace="urn:DefaultNamespace"

wobei der targetNamespace die URI des Ziel-Namensraums definiert. In der Regel wird hier mit dem DefaultNamespace gearbeitet, wobei anschließend auf die verschiedenen erforderlichen Namespaces verwiesen wird:

xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:apachesoap="http://xml.apache.org/xml-soap"
xmlns:impl="urn:DefaultNamespace" xmlns:intf="urn:DefaultNamespace"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/
"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">

Hier kommen beispielsweise die Standard-Namespaces für das Schema sowie SOAP zum Einsatz.In diesem Bereich, der in der Regel automatisch generiert wird, sind normalerweise keine Anpassungen erforderlich.'

<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions targetNamespace="urn:DefaultNamespace"
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:apachesoap="http://xml.apache.org/xml-soap"
xmlns:impl="urn:DefaultNamespace" xmlns:intf="urn:DefaultNamespace"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<wsdl:message name="GETPREISRequest">
<wsdl:part name="REISENUMMER" type="xsd:string"/>
</wsdl:message>
<wsdl:message name="GETPREISResponse">
<wsdl:part name="GETPREISReturn" type="xsd:double"/>
</wsdl:message>
<wsdl:portType name="PreisInfo">
<wsdl:operation name="GETPREIS" parameterOrder="REISENUMMER">
<wsdl:input message="impl:GETPREISRequest"
name="GETPREISRequest"/>
<wsdl:output message="impl:GETPREISResponse"
name="GETPREISResponse"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="DominoSoapBinding" type="impl:PreisInfo">
<wsdlsoap:binding style="rpc"
transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="GETPREIS">
<wsdlsoap:operation soapAction=""/>
<wsdl:input name="GETPREISRequest">
<wsdlsoap:body
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="urn:DefaultNamespace" use="encoded"/>
</wsdl:input>
<wsdl:output name="GETPREISResponse">
<wsdlsoap:body
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="urn:DefaultNamespace" use="encoded"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="PreisInfoService">
<wsdl:port binding="impl:DominoSoapBinding" name="Domino">
<wsdlsoap:address location="http://localhost"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>

Beschreibung der ersten Nachricht

Anschließend erfolgt die Beschreibung der ersten Nachricht:

<wsdl:message name="GETPREISRequest">
<wsdl:part name="REISENUMMER" type="xsd:string"/>
</wsdl:message>

Sie hat einen Namen und besteht aus nur einem Teil, der mit <wsdl:part> beschrieben wird. Dieser Teil gibt an, welche Information in der Nachricht übertragen wird. Nachrichten, die nur aus einer Zeichenkette bestehen, sind nicht unüblich, wenn ein Web Service sich eher wie eine Funktion verhält, an die ein oder wenige Werte übergeben werden, um genau einen Wert zurückgeliefert zu bekommen.

Es gibt aber auch viele Web Services, an die deutlich komplexere Dokumente mit einer Vielzahl von Informationen geliefert werden. Entsprechend wären in diesem Fall auch die Dokumentstrukturen komplexer. Eine zweite definierte Nachricht ist die Antwort, also

<wsdl:message name="GETPREISResponse">
<wsdl:part name="GETPREISReturn" type="xsd:double"/>
</wsdl:message>

Sie ist genauso einfach aufgebaut. Anschließend erfolgt die Definition eines Porttyps und der zugehörigen Operationen.

<wsdl:portType name="PreisInfo">
<wsdl:operation name="GETPREIS"
parameterOrder="REISENUMMER">
<wsdl:input message="impl:GETPREISRequest"
name="GETPREISRequest"/>
<wsdl:output message="impl:GETPREISResponse"
name="GETPREISResponse"/>
</wsdl:operation>
</wsdl:portType>

Der Port PreisInfo

Es gibt einen Port PreisInfo. Er bietet genau eine Operation an. Die Operation besteht aus den weiter oben beschriebenen Nachrichten zur Anforderung des Preises und zur Rückgabe des berechneten Wertes. Der portType beschreibt also den eigentlichen Dienst, der angeboten wird. Wenn man so möchte, werden innerhalb der Spezifikation eines Web Service mit den Port-Typesdie eigentlichen Dienste beschrieben – man könnte sie auch als Methoden oder Prozeduren bezeichnen, die aufgerufen werden können. Hier wird also definiert, was mit dem Web Service gemacht werden kann.

Weiter geht es mit der Bindung zu SOAP (Simple Object Access Protocol) für den Transport der Web Services. Dieser Block ist relativ lang, weil in ihm sowohl die eigentliche Art der Bindung als auch die Operationen beschrieben werden müssen. Der erste Teil ist die Definition der Bindung mit einem eindeutigen Namen:

<wsdl:binding name="DominoSoapBinding"
type="impl:PreisInfo">

Anschließend erfolgt die Festlegung der Art der Bindung. Hier erfolgt die Bindung in einem definierten Stil, in diesem Fall als RPC. Der Transport erfolgt über SOAP und HTTP.

<wsdlsoap:binding style="rpc"
transport="http://schemas.xmlsoap.org/soap/http"/>

Danach folgt die Operation, also in diesem Fall die Anforderung des Preises:

<wsdl:operation name="GETPREIS">
<wsdlsoap:operation soapAction=""/>
<wsdl:input name="GETPREISRequest">
<wsdlsoap:body
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="urn:DefaultNamespace" use="encoded"/>
</wsdl:input>
<wsdl:output name="GETPREISResponse">
<wsdlsoap:body
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="urn:DefaultNamespace" use="encoded"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>

Dafür wird eine Operation definiert, in deren Rahmen eine Eingabe und eine Ausgabe erfolgen, die sich auf die weiter oben spezifizierten Nachrichten beziehen. Hier wird letztlich nur festgelegt, in welcher Form das Encoding erfolgen soll.

Bezeichnung des Dienstes

Abschließend muss noch der Dienst als solches bezeichnet werden. Dabei werden sowohl der Bezug zu der weiter oben definierten Bindung als auch die Bindung zu einer Netzwerkadresse hergestellt:

<wsdl:service name="PreisInfoService">
<wsdl:port binding="impl:DominoSoapBinding"
name="Domino">
<wsdlsoap:address location="http://localhost"/>
</wsdl:port>
</wsdl:service>

Damit ist der Web Service beschrieben. Es fehlt nur noch das schließende Tag

</wsdl:definitions>

Diese Grundstruktur kann nun für beliebige andere Web Services verwendet werden, denn sie ist bei allen Web Services dieselbe:

Wenn man die auf den ersten Blick häufig etwas unübersichtlichen WSDL-Dokumente in die entsprechenden Blöcke zerlegt, wird das Ganze recht übersichtlich. Dabei kann es hilfreich sein, die Dokumente von hinten nach vorne zu betrachten. Denn zum Schluss wird der Service definiert. Davor finden sich die Bindungen von Operationen innerhalb dieses Web Service, die weiter vorne bei den Porttypen genau spezifiziert sind. Diese sind wiederum im Detail mit den Nachrichten fast zu Beginn des Dokuments beschrieben.