This is Chapter 6: WSDL Essentials from the book Web Services Essentials
(ISBN:0-596-00224-6) written by Ethan Cerami, published by O'Reilly & Associates.
© Copyright O'Reilly & Associates. All rights reserved.
Chapter 6
WSDL Essentials
WSDL is a specification defining how to describe web services in
a common XML grammar. WSDL describes four critical pieces of data:
- Interface information describing all publicly available
functions
- Data type information for all message requests and
message responses
- Binding information about the transport protocol to be
used
- Address information for locating the specified service
In a nutshell, WSDL represents a contract between the service
requestor and the service provider, in much the same way that a Java interface
represents a contract between client code and the actual Java object. The
crucial difference is that WSDL is platform- and language-independent and is
used primarily (although not exclusively) to describe SOAP services.
Using WSDL, a client can locate a web service and invoke any of
its publicly available functions. With WSDL-aware tools, you can also automate
this process, enabling applications to easily integrate new services with
little or no manual code. WSDL therefore represents a cornerstone of the web
service architecture, because it provides a common language for describing
services and a platform for automatically integrating those services.
This chapter covers all aspects of WSDL, including the following
topics:
- An overview of the WSDL specification, complete with
detailed explanations of the major WSDL elements
- Two basic WSDL examples to get you started
- A brief survey of WSDL invocation tools, including the
IBM Web Services Invocation Framework (WSIF), SOAP::Lite, and The Mind
Electric's GLUE platform
- A discussion of how to automatically generate WSDL
files from existing SOAP services
- An overview of using XML Schema types within WSDL,
including the use of arrays and complex types
The WSDL Specification
WSDL is an XML grammar for describing web services. The
specification itself is divided into six major elements:
definitions
- The
definitions element
must be the root element of all WSDL documents. It defines the name of the
web service, declares multiple namespaces used throughout the remainder of
the document, and contains all the service elements described here.
types
- The
types element
describes all the data types used between the client and server. WSDL is not
tied exclusively to a specific typing system, but it uses the W3C XML Schema
specification as its default choice. If the service uses only XML Schema
built-in simple types, such as strings and integers, the types element is not required. A full discussion of the
types element and XML Schema is deferred to the
end of the chapter.
message
- The
message element
describes a one-way message, whether it is a single message request or a
single message response. It defines the name of the message and contains
zero or more message part elements, which can
refer to message parameters or message return values.
portType
- The
portType element
combines multiple message elements to form a
complete one-way or round-trip operation. For example, a portType can combine one request and one response
message into a single request/response operation, most commonly used in SOAP
services. Note that a portType can (and
frequently does) define multiple operations.
binding
- The
binding element
describes the concrete specifics of how the service will be implemented on
the wire. WSDL includes built-in extensions for defining SOAP services, and
SOAP-specific information therefore goes here.
service
- The
service element
defines the address for invoking the specified service. Most commonly, this
includes a URL for invoking the SOAP service.
To help you keep the meaning of each element clear, Figure
6-1 offers a concise representation of the WSDL specification. As you
continue reading the remainder of the chapter, you may wish to refer back to
this diagram.
Figure 6-1. The WSDL specification in a nutshell
|
|
In addition to the six major elements, the WSDL specification
also defines the following utility elements:
documentation
- The
documentation element
is used to provide human-readable documentation and can be included inside
any other WSDL element.
import
- The
import element is used
to import other WSDL documents or XML Schemas. This enables more modular
WSDL documents. For example, two WSDL documents can import the same basic
elements and yet include their own service
elements to make the same service available at two physical addresses. Note,
however, that not all WSDL tools support the import functionality as of yet.
TIP: WSDL is not an official recommendation
of the W3C and, as such, has no official status within the W3C. WSDL
Version 1.1 was submitted to the W3C in March 2001. Original submitters
included IBM, Microsoft, Ariba, and a half dozen other companies. Most
probably, WSDL will be placed under the consideration of the new W3C Web
Services Activity's Web Services Description Working Group, which will
decide if the specification advances to an official recommendation status.
The WSDL Version 1.1 specification is available online at http://www.w3.org/TR/wsdl.
Basic WSDL Example:
HelloService.wsdl
To make the previously described WSDL concepts as concrete as
possible, let's examine our first sample WSDL file.
Example
6-1 provides a sample HelloService.wsdl document.
The document describes the HelloService from Chapter 4.
As you may recall, the service provides a single publicly
available function, called sayHello. The function
expects a single string parameter, and returns a single string greeting. For
example, if you pass the parameter world, the
service returns the greeting, "Hello, world!"
Example 6-1: HelloService.wsdl
<?xml version="1.0" encoding="UTF-8"?>
<definitions name="HelloService"
targetNamespace="http://www.ecerami.com/wsdl/HelloService.wsdl"
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://www.ecerami.com/wsdl/HelloService.wsdl"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<message name="SayHelloRequest">
<part name="firstName" type="xsd:string"/>
</message>
<message name="SayHelloResponse">
<part name="greeting" type="xsd:string"/>
</message>
<portType name="Hello_PortType">
<operation name="sayHello">
<input message="tns:SayHelloRequest"/>
<output message="tns:SayHelloResponse"/>
</operation>
</portType>
<binding name="Hello_Binding" type="tns:Hello_PortType">
<soap:binding style="rpc"
transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="sayHello">
<soap:operation soapAction="sayHello"/>
<input>
<soap:body
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="urn:examples:helloservice"
use="encoded"/>
</input>
<output>
<soap:body
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="urn:examples:helloservice"
use="encoded"/>
</output>
</operation>
</binding>
<service name="Hello_Service">
<documentation>WSDL File for HelloService</documentation>
<port binding="tns:Hello_Binding" name="Hello_Port">
<soap:address
location="http://localhost:8080/soap/servlet/rpcrouter"/>
</port>
</service>
</definitions>
The WSDL elements are discussed in the next section of this
chapter. As you examine each element in detail, you may want to refer to Figure
6-2, which summarizes the most important aspects of Example
6-1.
Figure 6-2. A bird's-eye view of HelloService.wsdl
|
|
definitions
The definitions element specifies
that this document is the HelloService. It also
specifies numerous namespaces that will be used throughout the remainder of
the document:
<definitions name="HelloService"
targetNamespace="http://www.ecerami.com/wsdl/HelloService.wsdl"
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://www.ecerami.com/wsdl/HelloService.wsdl"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
The use of namespaces is important for differentiating elements,
and it enables the document to reference multiple external specifications,
including the WSDL specification, the SOAP specification, and the XML Schema
specification.
The definitions element also
specifies a targetNamespace attribute. The targetNamespace is a convention of XML Schema that
enables the WSDL document to refer to itself. In Example
6-1, we specified a targetNamespace of http://www.ecerami.com/wsdl/HelloService.wsdl. Note,
however, that the namespace specification does not require that the document
actually exist at this location; the important point is that you specify a
value that is unique, different from all other namespaces that are defined.
Finally, the definitions element
specifies a default namespace: xmlns=http://schemas.xmlsoap.org/wsdl/.
All elements without a namespace prefix, such as message or portType, are
therefore assumed to be part of the default WSDL namespace.
message
Two message elements are defined. The
first represents a request message, SayHelloRequest,
and the second represents a response message, SayHelloResponse:
<message name="SayHelloRequest">
<part name="firstName" type="xsd:string"/>
</message>
<message name="SayHelloResponse">
<part name="greeting" type="xsd:string"/>
</message>
Each of these messages contains a single part element. For the request, the part specifies the
function parameters; in this case, we specify a single firstName parameter. For the response, the part specifies
the function return values; in this case, we specify a single greeting return value.
The part element's type attribute specifies an XML Schema data type. The
value of the type attribute must be specified as an
XML Schema QName--this means that the value of the
attribute must be namespace-qualified. For example, the firstName type attribute is
set to xsd:string; the xsd prefix references the namespace for XML Schema,
defined earlier within the definitions element.
If the function expects multiple arguments or returns multiple
values, you can specify multiple part elements.
portType
The portType element defines a single
operation, called sayHello. The operation itself
consists of a single input message (SayHelloRequest) and a single output message (SayHelloResponse):
<portType name="Hello_PortType">
<operation name="sayHello">
<input message="tns:SayHelloRequest"/>
<output message="tns:SayHelloResponse"/>
</operation>
</portType>
Much like the type attribute defined
earlier, the message attribute must be specified as
an XML Schema QName. This means that the value of the attribute must be
namespace-qualified. For example, the input element
specifies a message attribute of tns:SayHelloRequest; the tns
prefix references the targetNamespace defined
earlier within the definitions element.
WSDL supports four basic patterns of operation:
- One-way
- The service receives a message. The operation
therefore has a single
input element.
- Request-response
- The service receives a message and sends a response.
The operation therefore has one
input element,
followed by one output element (illustrated
previously in Example
6-1). To encapsulate errors, an optional fault element can also be specified.
- Solicit-response
- The service sends a message and receives a response.
The operation therefore has one
output element,
followed by one input element. To encapsulate
errors, an optional fault element can also be
specified.
- Notification
- The service sends a message. The operation therefore
has a single
output element.
These patterns of operation are also shown in Figure
6-3. The request-response pattern is most commonly used in SOAP services.
Figure 6-3. Operation patterns supported by WSDL 1.1
|
|
binding
The binding element provides specific
details on how a portType operation will actually
be transmitted over the wire. Bindings can be made available via multiple
transports, including HTTP GET, HTTP POST, or SOAP. In fact, you can specify
multiple bindings for a single portType.
The binding element itself specifies
name and type
attributes:
<binding name="Hello_Binding" type="tns:Hello_PortType">
The type attribute references the
portType defined earlier in the document. In our
case, the binding element therefore references
tns:Hello_PortType, defined earlier in the
document. The binding element is therefore saying, "I will provide specific
details on how the sayHello operation will be
transported over the Internet."
SOAP binding
WSDL 1.1 includes built-in extensions for SOAP 1.1. This enables
you to specify SOAP-specific details, including SOAP headers, SOAP encoding
styles, and the SOAPAction HTTP header. The SOAP
extension elements include:
soap:binding
- This element indicates that the binding will be made
available via SOAP. The
style attribute indicates
the overall style of the SOAP message format. A style value of rpc specifies
an RPC format. This means that the body of the SOAP request will include a
wrapper XML element indicating the function name. Function parameters are
then embedded inside the wrapper element. Likewise, the body of the SOAP
response will include a wrapper XML element that mirrors the function
request. Return values are then embedded inside the response wrapper
element.
- A
style value of document specifies an XML document call format. This
means that the request and response messages will consist simply of XML
documents. The document style is flatter than the rpc style and does not require the use of wrapper
elements. (See the upcoming note for additional details.)
- The
transport attribute
indicates the transport of the SOAP messages. The value
http://schemas.xmlsoap.org/soap/http
indicates the SOAP HTTP transport, whereas http://schemas.xmlsoap.org/soap/smtp indicates the SOAP
SMTP transport.
soap:operation
- This element indicates the binding of a specific
operation to a specific SOAP implementation. The
soapAction attribute specifies that the SOAPAction HTTP header be used for identifying the
service. (See Chapter 3 for details on the SOAPAction header.)
soap:body
- This element enables you to specify the details of
the input and output messages. In the case of HelloWorld, the
body element specifies the SOAP encoding style and the
namespace URN associated with the specified service.
TIP: The choice between the rpc style and the document
style is controversial. The topic has been hotly debated on the WSDL
newsgroup (http://groups.yahoo.com/group/wsdl).
The debate is further complicated because not all WSDL-aware tools even
differentiate between the two styles. Because the rpc style is more in line with the SOAP examples from
previous chapters, I have chosen to stick with the rpc style for all the examples within this chapter.
Note, however, that most Microsoft .NET WSDL files use the document style.
service
The service element specifies the
location of the service. Because this is a SOAP service, we use the soap:address element, and specify the local host address
for the Apache SOAP rpcrouter servlet: http://localhost:8080/soap/servlet/rpcrouter.
Note that the service element includes a documentation element to provide human-readable
documentation.
WSDL Invocation Tools, Part I
Given the WSDL file in Example
6-1, you could manually create a SOAP client to invoke the service. A
better alternative is to automatically invoke the
service via a WSDL invocation tool. (See Figure
6-4.)
Figure 6-4. WSDL invocation tools
|
|
Many WSDL invocation tools already exist. This section provides
a brief overview of three invocation tools.
GLUE
The Mind Electric provides a complete web service platform
called GLUE (available at http://www.themindelectric.com/).
The platform itself provides extensive support for SOAP, WSDL, and UDDI. Some
of its advanced functionality, including support for complex data types, will
be explored later in this chapter.
For now, you can try out the GLUE invoke command-line tool. Here is the command-line usage:
usage: invoke URL method arg1 arg2 arg3...
For example, to invoke the HelloService, make sure that your
Apache Tomcat server is running, and place the HelloService.wsdl file within a publicly available
directory. Then, issue the following command:
invoke http://localhost:8080/wsdl/HelloService.wsdl sayHello World
Once invoked, GLUE will immediately download the specified WSDL
file, invoke the sayHello method, and pass World as a parameter. GLUE will then automatically
display the server response:
Output: result = Hello, World!
That's all there is to it!
GLUE also supports an excellent logging facility that enables
you to easily view all SOAP messages. To activate the logging facility, set
the electric.logging system property. The easiest
option is to modify the invoke.bat file. The original
file looks like this:
call java electric.glue.tools.Invoke %1 %2 %3 %4 %5 %6 %7 %8 %9
Modify the file to include the logging property via the -D option to the Java interpreter:
call java -Delectric.logging="SOAP" electric.glue.tools.Invoke %1 %2 %3 %4
%5 %6 %7 %8 %9
When you invoke the HelloService, GLUE now generates the
following output:
LOG.SOAP: request to http://207.237.201.187:8080/soap/servlet/rpcrouter
<?xml version='1.0' encoding='UTF-8'?>
<soap:Envelope
xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xmlns:xsd='http://www.w3.org/2001/XMLSchema'
xmlns:soap='http://schemas.xmlsoap.org/soap/
envelope/' xmlns:soapenc='http://schemas.xmlsoap.org/soap/encoding/'
soap:encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'>
<soap:Body>
<n:sayHello xmlns:n='urn:examples:helloservice'>
<firstName xsi:type='xsd:string'>World</firstName>
</n:sayHello>
</soap:Body>
</soap:Envelope>
LOG.SOAP: response from http://207.237.201.187:8080/soap/servlet/rpcrouter
<?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/1999/XMLSchema-instance'
xmlns:xsd='http://www.w3.org/1999/XMLSchema'>
<SOAP-ENV:Body>
<ns1:sayHelloResponse
xmlns:ns1='urn:examples:helloservice'
SOAP-ENV:encodingStyle=
'http://schemas.xmlsoap.org/soap/encoding/'>
<return xsi:type='xsd:string'>Hello, World!</return>
</ns1:sayHelloResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
result = Hello, World!
To view additional HTTP information, just set electric.logging to SOAP,HTTP.
SOAP::Lite for Perl
SOAP::Lite for Perl, written by Paul Kulchenko, also provides
limited support for WSDL. The package is available at http://www.soaplite.com.
Example
6-2 provides a complete Perl program for invoking the HelloService.
Example 6-2: Hello_Service.pl
use SOAP::Lite;
print "Connecting to Hello Service...\n";
print SOAP::Lite
-> service('http://localhost:8080/wsdl/HelloService.wsdl')
-> sayHello ('World');
The program generates the following output:
Connecting to Hello Service...
Hello, World!
IBM Web Services Invocation Framework (WSIF)
Finally, IBM has recently released WSIF. The package is
available at http://www.alphaworks.ibm.com/tech/wsif.
Much like GLUE, WSIF provides a simple command-line option for
automatically invoking WSDL services. For example, the following command:
java clients.DynamicInvoker http://localhost:8080/wsdl/HelloService.wsdl
sayHello World
generates the following output:
Reading WSDL document from 'http://localhost:8080/wsdl/HelloService.wsdl'
Preparing WSIF dynamic invocation
Executing operation sayHello
Result:
greeting=Hello, World!
Done!
Basic WSDL Example: XMethods eBay Price Watcher Service
Before moving on to more complicated WSDL examples, let's
examine another relatively simple one. Example
6-3 provides a WSDL file for the XMethods eBay Price Watcher Service. The
service takes an existing eBay auction ID, and returns the value of the
current bid.
Example 6-3: eBayWatcherService.wsdl (reprinted with permission of
XMethods, Inc.)
<?xml version="1.0"?>
<definitions name="eBayWatcherService"
targetNamespace=
"http://www.xmethods.net/sd/eBayWatcherService.wsdl"
xmlns:tns="http://www.xmethods.net/sd/eBayWatcherService.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="getCurrentPriceRequest">
<part name="auction_id" type = "xsd:string"/>
</message>
<message name="getCurrentPriceResponse">
<part name="return" type = "xsd:float"/>
</message>
<portType name="eBayWatcherPortType">
<operation name="getCurrentPrice">
<input
message="tns:getCurrentPriceRequest"
name="getCurrentPrice"/>
<output
message="tns:getCurrentPriceResponse"
name="getCurrentPriceResponse"/>
</operation>
</portType>
<binding name="eBayWatcherBinding" type="tns:eBayWatcherPortType">
<soap:binding
style="rpc"
transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="getCurrentPrice">
<soap:operation soapAction=""/>
<input name="getCurrentPrice">
<soap:body
use="encoded"
namespace="urn:xmethods-EbayWatcher"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
</input>
<output name="getCurrentPriceResponse">
<soap:body
use="encoded"
namespace="urn:xmethods-EbayWatcher"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
</output>
</operation>
</binding>
<service name="eBayWatcherService">
<documentation>
Checks current high bid for an eBay auction
</documentation>
<port name="eBayWatcherPort" binding="tns:eBayWatcherBinding">
<soap:address
location="http://services.xmethods.net:80/soap/servlet/rpcrouter"/>
</port>
</service>
</definitions>
Here is an overview of the main WSDL elements:
messages
- Two messages are defined:
getCurrentPriceRequest and getCurrentPriceResponse. The request message contains a
single string parameter; the response message contains a single float
parameter.
portType
- A single operation,
getCurrentPrice, is defined. Again, we see the
request/response operation pattern.
binding
- The
binding element
specifies HTTP SOAP as the transport. The soapAction attribute is left as an empty string ("").
service
- This element specifies that the service is available
at http://services.xmethods.net/soap/servlet/rpcrouter.
To access the eBay watcher service, you can use any of the WSDL
invocation tools defined earlier. For example, the following call to GLUE:
invoke http://www.xmethods.net/sd/2001/EBayWatcherService.wsdl
getCurrentPrice 1271062297
retrieves the current bid price for a Handspring Visor Deluxe:
result = 103.5
TIP: The XMethods web site (http://www.xmethods.net/) provides
dozens of sample SOAP and .NET services. Nearly all of these services
include WSDL files and therefore provide an excellent opportunity for
learning WSDL in detail. As you browse the XMethods directory, try
interfacing with the specified services via any of the WSDL invocation tools
described here. Quite likely, you will be amazed at how easy it is to
integrate and invoke new services.