Friday, October 28, 2011

Understanding WSDL - Basics

XML makes it possible for developers to expose valuable resources in a highly interoperable fashion, where a resource is any type of application or data store used within an organization. The XML Web services architecture defines a standard mechanism for making resources available via XML messaging. Being able to access a resource by simply transmitting XML messages over standard protocols like TCP, HTTP, or SMTP greatly lowers the bar for potential consumers. The term "Web service" (or simply "service") typically refers to the piece of code implementing the XML interface to a resource, which may otherwise be difficult to access (see Figure 1).
Figure 1: Resources and services
This architecture makes it possible for any consumer with XML support to integrate with Web service applications. However, in order to accomplish this, consumers must determine the precise XML interface along with other miscellaneous message details a priori. XML Schema can partially fill this need because it allows developers to describe the structure of XML messages. XML Schema alone, however, can't describe the additional details involved in communicating with a Web service.
A schema definition simply tells you what XML messages may be used but not how they relate to each other. For example, if there's an XML element named Add and another named AddResponse, it's likely they're related to each other but there's no way to indicate that in the schema. Hence, in addition to being aware of the messages, consumers must also be aware of the possible message exchanges supported by the Web service (e.g., if you send an Add message, you get an AddResponse message back).
A message exchange is also referred to as an operation. Operations are what consumers care about most since they're the focal point of interacting with the service (see Figure 2). Whenever I approach a new Web service, I first inspect its list of supported operations to get an overall feel for what it offers.
Figure 2: Messages and operations
It's common for developers to group related operations into interfaces. Consumers must be aware of these groupings since it impacts the way they write their code. This is especially important to developers working with Web services in object-oriented environments since the XML interfaces can map to programmatic interfaces (or abstract classes) in their language of choice.
Consumers must also know what communication protocol to use for sending messages to the service, along with the specific mechanics involved in using the given protocol such as the use of commands, headers, and error codes. A binding specifies the concrete details of what goes on the wire by outlining how to use an interface with a particular communication protocol. A binding also influences the way abstract messages are encoded on the wire by specifying the style of service (document vs. RPC) and the encoding mechanism (literal vs. encoded). Check out Understanding SOAP for more background on these concepts.
A service can support multiple bindings for a given interface, but each binding should be accessible at a unique address identified by a URI, also referred to as a Web service endpoint (see Figure 3).
Figure 3: Interfaces and bindings
Consumers must discover all of the details described above before they can interact with a Web service. The Web Services Description Language (WSDL) provides an XML grammar for describing these details. WSDL picks up where XML Schema left off by providing a way to group messages into operations and operations into interfaces. It also provides a way to define bindings for each interface and protocol combination along with the endpoint address for each one. A complete WSDL definition contains all of the information necessary to invoke a Web service. Developers that want to make it easy for others to access their services should make WSDL definitions available.
WSDL plays an important role in the overall Web services architecture since it describes the complete contract for application communication (similar to the role of IDL in the DCOM architecture). Although other techniques exist for describing Web services, the WS-I Basic Profile Version 1.0 mandates the use of WSDL and XML Schema (see Figure 4) for describing Web services. This helps ensure interoperability at the service description layer.
Figure 4: WS-I Basic Profile 1.0 technologies
Since WSDL is a machine-readable language (e.g., it's just an XML file), tools and infrastructure can be easily built around it. Today developers can use WSDL definitions to generate code that knows precisely how to interact with the Web service it describes. This type of code generation hides the tedious details involved in sending and receiving SOAP messages over different protocols and makes Web services approachable by the masses.
The Microsoft® .NET Framework comes with a command-line utility named wsdl.exe that generates classes from WSDL definitions. Wsdl.exe can generate one class for consuming the service and another for implementing the service. (Apache Axis comes with a similar utility named WSDL2Java that performs the same function for Java classes.) Classes generated from the same WSDL definition should be able to communicate with each other through the WSDL-provided interfaces, regardless of the programming languages in use (see Figure 5).
Figure 5: WSDL and code generation
WSDL 1.1 is considered the de-facto standard today because of it's industry-wide support. Most Web services toolkits support WSDL 1.1, but there have been some interoperability problems across the different implementations. Many developers believe that the extensive flexibility of WSDL (and the resulting complexity) is the fundamental source of these problems. The WS-I has helped resolve some of these issues by encouraging developers to use certain parts of the specification and discouraging them from using others.
The W3C is actively working on the next "official" version of WSDL, WSDL 1.2, but it's currently only a Working Draft and not supported by the mainstream toolkits, if any. The remainder of this article discusses the details of a WSDL 1.1 definition and highlights some of the WS-I basic profile suggestions along the way.

WSDL Basics

A WSDL definition is an XML document with a root definition element from the http://schemas.xmlsoap.org/wsdl/ namespace. The entire WSDL schema is available at http://schemas.xmlsoap.org/wsdl/ for your reference. The definitions element may contain several other elements including types, message, portType, binding, and service, all of which come from the http://schemas.xmlsoap.org/wsdl/ namespace. The following illustrates the basic structure of a WSDL definition:
<!-- WSDL definition structure -->
<definitions 
    name="MathService"
targetNamespace="http://example.org/math/"
xmlns="http://schemas.xmlsoap.org/wsdl/"
>
   <!-- abstract definitions -->
    <types> ...
    <message> ...
   <portType> ...

   <!-- concrete definitions -->
   <binding> ...
   <service> ...
</definition>
Notice that you must specify a target namespace for your WSDL definition, just like you would for an XML Schema definition. Anything that you name in the WSDL definition (like a message, portType, binding, etc.) automatically becomes part of the WSDL definition's target namespace defined by the targetNamespace attribute. Hence, when you reference something by name in your WSDL file, you must remember to use a qualified name.
The first three elements (types, message, and portType) are all abstract definitions of the Web service interface. These elements constitute the programmatic interface that you typically interface with in your code. The last two elements (binding and service) describe the concrete details of how the abstract interface maps to messages on the wire. These details are typically handled by the underlying infrastructure, not by your application code. Table 1 provides brief definitions for each of these core WSDL elements and the remaining sections discuss them in more detail.
Table 1. WSDL Elements
Element Name Description
types A container for abstract type definitions defined using XML Schema
message A definition of an abstract message that may consist of multiple parts, each part may be of a different type
portType An abstract set of operations supported by one or more endpoints (commonly known as an interface); operations are defined by an exchange of messages
binding A concrete protocol and data format specification for a particular portType
service A collection of related endpoints, where an endpoint is defined as a combination of a binding and an address (URI)

Types

The WSDL types element is a container for XML Schema type definitions. The type definitions you place here are referenced from higher-level message definitions in order to define the structural details of the message. Officially, WSDL 1.1 allows the use of any type definition language, although it strongly encourages the use of XML Schema and treats it as its intrinsic type system. The WS-I enforces this by mandating the use of XML Schema in the Basic Profile 1.0.
The types element contains zero or more schema elements from the http://www.w3.org/2001/XMLSchema namespace. The basic structure of the types element (with namespaces omitted) is as follows (* means zero or more):
<definitions .... >
    <types>
        <xsd:schema .... />*
    </types>
</definitions>
You can use any XML Schema construct within the schema element, such simple type definitions, complex type definitions, and element definitions. The following WSDL fragment contains an XML Schema definition that defines four elements of type MathInput (Add, Subtract, Multiply, and Divide) and four elements of type MathOutput (AddResponse, SubtractResponse, MultiplyResponse, and DivideResponse).
<definitions 
  xmlns="http://schemas.xmlsoap.org/wsdl/" 
  xmlns:xs="http://www.w3.org/2001/XMLSchema" 
  xmlns:y="http://example.org/math/" 
  xmlns:ns="http://example.org/math/types/" 
  targetNamespace="http://example.org/math/"
>
  <types>
    <xs:schema 
      targetNamespace="http://example.org/math/types/" 
      xmlns="http://example.org/math/types/" 
    >
     <xs:complexType name="MathInput">
       <xs:sequence>
      <xs:element name="x" type="xs:double"/>
      <xs:element name="y" type="xs:double"/>
       </xs:sequence>
     </xs:complexType>
     <xs:complexType name="MathOutput">
       <xs:sequence>
         <xs:element name="result" type="xs:double"/>
       </xs:sequence>
     </xs:complexType>
     <xs:element name="Add" type="MathInput"/>
     <xs:element name="AddResponse" type="MathOutput"/>
     <xs:element name="Subtract" type="MathInput"/>
     <xs:element name="SubtractResponse" type="MathOutput"/>
     <xs:element name="Multiply" type="MathInput"/>
     <xs:element name="MultiplyResponse" type="MathOutput"/>
     <xs:element name="Divide" type="MathInput"/>
     <xs:element name="DivideResponse" type="MathOutput"/>
    </xs:schema>
  </types>
   ...
</definitions>
If you're new to XML Schema and need to ramp up, check out Understanding XML Schema. Once you have your XML Schema types defined, the next step is to define the logical messages that will constitute your operations.

Messages

The WSDL message element defines an abstract message that can serve as the input or output of an operation. Messages consist of one or more part elements, where each part is associated with either an element (when using document style) or a type (when using RPC style). The basic structure of a message definition is as follows (* means zero or more and ? means optional):
<definitions .... >
    <message name="nmtoken"> *
        <part name="nmtoken" element="qname"? type="qname"?/> *
    </message>
</definitions>
The messages and parts must be named making it possible to refer to them from elsewhere in the WSDL definition. If you're defining an RPC style service, the message parts represent the method's parameters. In this case, the name of the part becomes the name of an element in the concrete message and its structure is determined by the supplied type attribute. If you're defining a document style service, the parts simply refer to the XML elements that are placed within the body (referenced by the element attribute). The following example contains several message definitions that refer to elements by name:
<definitions 
  xmlns="http://schemas.xmlsoap.org/wsdl/" 
  xmlns:xs="http://www.w3.org/2001/XMLSchema" 
  xmlns:y="http://example.org/math/" 
  xmlns:ns="http://example.org/math/types/" 
  targetNamespace="http://example.org/math/"
>
   ...
   <message name="AddMessage">
      <part name="parameter" element="ns:Add"/>
   </message>
   <message name="AddResponseMessage">
      <part name="parameter" element="ns:AddResponse"/>
   </message>
   <message name="SubtractMessage">
      <part name="parameter" element="ns:Subtract"/>
   </message>
   <message name="SubtractResponseMessage">
      <part name="parameter" element="ns:SubtractResponse"/>
   </message>
   ...
</definitions>
Although the message parts typically refer to XML types or elements, they can also refer to non-XML types. This allows WSDL to represent a wide range of messages that contain a mixture of data formats, as is the case with multi-part MIME.
Note   The message and type definitions in WSDL are considered to be abstract definitions. This means you don't know how they'll appear in the concrete message format until you've applied a binding to them. For example, if you use one abstract message with two different bindings, it's possible that the two concrete messages will look different. Only with 'literal' bindings are the abstract definitions guaranteed to accurately describe the concrete message format. See the Bindings section for more details.

Interfaces (portTypes)

The WSDL portType element defines a group of operations, also known as an interface in most environments. Unfortunately, the term "portType" is quite confusing so you're better off using the term "interface" in conversation. WSDL 1.2 has already removed "portType" and replaced it with "interface" in the current draft of the language.
A portType element contains zero or more operation elements. The basic structure of a portType is as follows (* means zero or more):
<definitions .... >
    <portType name="nmtoken">
        <operation name="nmtoken" .... /> *
    </portType>
</definitions>
Each portType must be given a unique name making it possible to refer to it from elsewhere in the WSDL definition. Each operation element contains a combination of input and output elements, and when you have an output element you can also have a fault element. The order of these elements defines the message exchange pattern (MEP) supported by the given operation.
For example, an input element followed by an output element defines a request-response operation, while an output element followed by an input element defines a solicit-response operation. An operation that only contains an input element defines a one-way operation, while an operation that only contains an output element defines a notification operation. Table 2 describes the four MEP primitives defined by WSDL.
Table 2. Message Exchange Patterns
MEP Description
One-way The endpoint receives a message.
Request-response The endpoint receives a message and sends a correlated message.
Solicit-response The endpoint sends a message and receives a correlated message.
Notification The endpoint sends a message.
The input, output, and fault elements used in an operation must refer to a message definition by name. The following example defines a portType named MathInterface that consists of four math operations: Add, Subtract, Multiply, and Divide.
<definitions 
  xmlns="http://schemas.xmlsoap.org/wsdl/" 
  xmlns:xs="http://www.w3.org/2001/XMLSchema" 
  xmlns:y="http://example.org/math/" 
  xmlns:ns="http://example.org/math/types/" 
  targetNamespace="http://example.org/math/"
>
   ...
   <portType name="MathInterface">
      <operation name="Add">
         <input message="y:AddMessage"/>
         <output message="y:AddResponseMessage"/>
      </operation>
      <operation name="Subtract">
         <input message="y:SubtractMessage"/>
         <output message="y:SubtractResponseMessage"/>
      </operation>
      <operation name="Multiply">
         <input message="y:MultiplyMessage"/>
         <output message="y:MultiplyResponseMessage"/>
      </operation>
      <operation name="Divide">
         <input message="y:DivideMessage"/>
         <output message="y:DivideResponseMessage"/>
      </operation>
   </portType>   
    ...
</definitions>
A portType is still considered an abstract definition because you don't know how its messages are represented on the wire until you apply a binding.

No comments:

Post a Comment

Blog Archive