A Busy Developers Guide to WSDL 1.1

By Sam Ruby, February 15, 2002.

This document demonstrates how the process of achieving meaningful interoperation between different environments can be achieved in a simpler and less error prone manner by applying some of the basic concepts described in WSDL 1.1 .  The DIY Web Services Tutorial will be used as an example throughout this document.  A basic understanding of the current mechanisms used to invoke web services from various environments is presumed.  Familiarity with SCNS and WSDL FM would be helpful.  Knowledge of the underlying SOAP 1.1 protocol is not a requirement.

Part II of this document covers adding type information. Part III of this document covers document literal web services.

Overview #

When picking apart a SOAP message or a WSDL document, it is not hard to see how you can extract the information that is relevant to you and ignore the rest.  But somehow this process doesn't seem reversible.  The truth is quite the opposite: once you realize that you are simply describing a message that you would accept, and not saying anything about what other messages you might also accept.  A concrete example may help illustrate the point here.  Imagine an environment where operations are not case sensitive.  As there is no requirement to enumerate all the permutations you can accept, simply name one you would accept.  Similarly, if your environment does not access objects based on the namespace of the body element, you need only identify one namespace that you would accept, which in this case would be pretty much anything, actually.  So by filling in every blank with answers you do know, and providing reasonable defaults for the rest, you can provide clients all the information they need to access your web service.

The next few sections of this document document will construct a working WSDL document in chunks and use the <import> facility to link the pieces together.  Then the actual code which makes use of this document will be presented.

Declaring the portType #

A port is simply a collection of operations.  Many programming languages refer to this as a library, a module, or a class.  But this is the world of messaging, so the connection points are called ports, and an abstract definition of a port is called a port type.  In this case, we are looking at an abstract definition of the helloWorld procedure.  Here's how this would be defined in WSDL:

<?xml version="1.0" encoding="utf-8"?>
<definitions 
  xmlns:s="http://www.w3.org/2001/XMLSchema" 
  xmlns:tns="uri:diy" targetNamespace="uri:diy" 
  xmlns="http://schemas.xmlsoap.org/wsdl/">

  <types/>

  <message name="helloWorldRequest">
    <part name="name" type="s:anyType"/>
  </message>

  <message name="helloWorldResponse">
    <part name="helloWorldResult" type="s:anyType"/>
  </message>

  <portType name="tutorialPort">
    <operation name="helloWorld">
      <input message="tns:helloWorldRequest"/>
      <output message="tns:helloWorldResponse"/>
    </operation>
  </portType>
</definitions>

In plain English, we are defining the helloWorld operation for the tutorial port in the uri:diy namespace.  This operation has an input message called a request and output message called a response.  Each of these messages consist of a single part which can be of any type.  While I don't recommend typeless interfaces in general (more on this in a future essay), I do so here both to show that it can be done and to keep this example simple.  Note also the empty <types/> element.  This is where additional types would be defined.

At this point, one might wonder why messages are broken out to this level of granularity.  The reason for this is that in a larger system you might want to reuse messages with the output of one operation being the input to the next.

Binding this port to SOAP #

PortTypes are protocol independent.  While the there are many choices for protocols, for the purpose of this document we are going to pick one: RPC style SOAP requests over HTTP with SOAP encoding.  OK, now that I have named the protocol in words, lets see how this is expressed in WSDL:

<?xml version="1.0" encoding="utf-8"?>
<definitions 
  xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" 
  xmlns:tns="uri:diy" targetNamespace="uri:diy" 
  xmlns="http://schemas.xmlsoap.org/wsdl/">

  <import namespace="uri:diy" location="porttype.wsdl"/> 

  <binding name="tutorialSoap" type="tns:tutorialPort">
    <soap:binding style="rpc"
      transport="http://schemas.xmlsoap.org/soap/http"/>
    <operation name="helloWorld">
      <soap:operation soapAction="/radio" style="rpc"/>
      <input>
        <soap:body use="encoded" namespace="uri:tutorial" 
          encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
      </input>
      <output>
        <soap:body use="encoded" namespace="uri:tutorial" 
          encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
      </output>
    </operation>
  </binding>
</definitions>

The first thing this definition does is to import the previously defined portType.  Then it defines a SOAP binding using an http transport using the rpc style.  The helloWorld operation is further qualified to contain a soapAction, and the bodies of both the input and output messages are defined with the appropriate encoding and namespace.  Again, if your implementation doesn't particularly care about namespaces (it need not, after all), then simply provide some reasonable and meaningful default.

While this may seem like a lot of work, realize that this is exactly the same information that you needed to provide on a call to soap.rpc.client.

Finally note that this definition provides much more flexibility than you may need.  For example, you might not envision a need for specifying different encodings for input and output messages.  That's OK, for now, simply focus on defining what messages you will accept and will produce. 

Defining the service. #

Again, we start by importing the work done so far.  Then a service is defined with a single instance of a the abstract tutorialPort type which is bound to the tutorialSOAP binding.  Finally, the information on the actual endpoint URL is provided.  The result follows:

<?xml version="1.0" encoding="utf-8"?>
<definitions
  xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
  xmlns:tns="uri:diy" targetNamespace="uri:diy"
  xmlns="http://schemas.xmlsoap.org/wsdl/">

  <import namespace="uri:diy" location="binding.wsdl"/>

  <service name="tutorial">
    <document>
      For a complete description of this service, go to the following URL:
      <a href="http://radio.userland.com/webServicesTutorial">http://radio.userland.com/webServicesTutorial</a>
    </document>

    <port name="tutorialPort" binding="tns:tutorialSoap">
      <soap:address location="http://127.0.0.1:5335/"/>
    </port>
  </service>
</definitions>

Also note the document that was added.  Truth be told, this should have been done every step of the way.  But in any case, the WSDL is at this point complete.  Now lets see this in action.

Accessing this Web Service from Apache Axis #

The first thing to do is to use the WSDL2Java tool to produce Java classes from this WSDL.  Compile the generated Java classes along with the following test program:

import diy.*;

public class Test {
  public static void main(String[] args) throws Exception {
    TutorialPort tutorial = new TutorialLocator().getTutorialPort();
    System.out.println(tutorial.helloWorld(args[0]));
  }
}
Now invoke the result using

java Test Dave

And Murphy willing (and presuming that you successfully installed and got working the DIY tutorial web service), the result will be:

Hello Dave!

Conclusion #

If you compare the amount of code it takes to directly invoke a SOAP web service without the benefit of a WSDL description and the amount of code it takes to invoke the same service based on a WSDL definition, the differences are dramatic.  The reason is simple: administrative details such as parameter names and soap action are taken care of for you.  Furthermore when you consider that this same definition can be used to make life easier (modulo the upcoming interoperability effort) - not only for Radio and Axis users, but also for users of many others implementations such as SOAP::Lite, PHP, or even the .Net framework - the case for a standard, interoperable, web services description language is fairly compelling.

Commentary #

Most importantly, treat any WSDL you define (either programmatically or manually) as a starting point.  Others may wish to refine it or provide alternate values for ones that you defaulted or to add type information.  This is natural, particularly if you are defining a WebService that can be implemented in many different environments.  More helpful advice can be found here.  And a good source for additional information on what can be done with a WSDL can be found here.

Search

Valid XHTML 1.1!