9.1 Basic WSDL


The Web Service Definition Language (WSDL) is an XML application originally co- authored by a team of representatives from Microsoft and IBM. The current version accepted as a technical recommendation by the W3C is 1.1, which was released in March 2001. Currently, Version 1.2 of the specification is under active development under the broader scope of the W3C's working- group on web services.

WSDL is a major component behind the cross-platform nature of Microsoft's .NET platform. Many web-services platforms offer generation of WSDL descriptions as a feature of the development process, closely associating the creation of the software with formally defining the interface. On the client side, tools can generate object classes, or even whole applications, from the description as an input.

9.1.1 Starting Simple

To begin with, the XML document in Example 9-1 shows a very simple WSDL document, one that defines only the GetBook operation from the sample project developed in the previous chapters.

Example 9-1. Basic WSDL describing the GetBook operation
 <?xml version="1.0"?> <  definitions  name="WLC#GetBook"     targetNamespace="urn:simple" xmlns:tns="urn:simple"     xmlns:xsd="http://www.w3.org/2001/XMLSchema"     xmlns:soap="  http://schemas.xmlsoap.org/wsdl/soap/  "     xmlns="http://schemas.xmlsoap.org/wsdl/">  <types>  <xsd:schema xmlns="http://www.w3.org/2001/XMLSchema"          targetNamespace="urn:simple">       <xsd:complexType name="BookData">         <xsd:all>           <xsd:element name="isbn"  type="xsd:string" />           <xsd:element name="title" type="xsd:string" />           <xsd:element name="url"   type="xsd:anyURI" />         </xsd:all>       </xsd:complexType>     </xsd:schema>   </  types  >   <  message  name="GetBookRequest">     <  part  name="isbn" type="xsd:string" />  </message>  <  message  name="GetBookResponse">     <  part  name="return" type="tns:BookData" />   </message>   <  portType  name="simpleWishListExample">     <  operation  name="GetBook">       <  input  message="tns:GetBookRequest" />       <  output  message="tns:GetBookResponse" />  </operation>   </portType>  <  binding  name="GetBookBinding"            type="tns:simpleWishListExample">     <soap:binding style="rpc"          transport="http://schemas.xmlsoap.org/soap/http" />     <  operation  name="GetBook">       <soap:operation soapAction="urn:/WishListCustomer">       <  input  >         <soap:body use="encoded"             namespace="urn:/WishListCustomer" />       </  input  >       <  output  >         <soap:body use="encoded"              namespace="urn:/WishListCustomer" />       </  output  >  </operation>   </binding>  <  service  name="GetBookSimple">     <  port  name="simpleWishListExample"           binding="tns:GetBookBinding">       <soap:address location="http://localhost:9000/" />     </  port  >  </service>   </definitions>  

The emphasized tags are the WSDL elements that will be explained later. This is just an example, of course. An actual WSDL specification for the service would cover all the operations, and define types, such as BookData , in terms of the distinction between partial and complete data retrieval.

9.1.2 The Parts of a WSDL Document

The basic structure of a WSDL document is shown in Figure 9-1. Services are made up of ports , which in turn are built up from port types and bindings . The portType and binding sections describe operations , which in turn are built from descriptions of messages . A message simply groups related data with specification of the type each data element conforms to.

Figure 9-1. WSDL document structure
figs/pwsp_0901.gif

The first three groups of concepts in the figure are labeled abstract elements , while the last two are labeled concrete elements . Abstracts define parts of the description that are purely informational: datatypes, message content, and so on. Those factors defined as concrete define the more tangible elements: association of abstract elements to actual transport methods and the definition of the service itself in terms of communication address and protocol.

The WSDL jargon can be confusing. In WSDL terms, a port describes an operation. It's generally a given routine in the API being exposed. In general network programming language, port usually refers to a socket endpoint. The binding tags associate ports with transport mechanisms, such as SOAP. This concept is similar to that of binding a socket to a specific address and port in traditional network programming.

As we go through the individual elements of WSDL, we'll build a full WSDL specification for the services built in the previous two chapters.

9.1.2.1 Starting a WSDL document

A WSDL document is a set of definitions, starting from type definitions (if needed) and culminating in the service definitions. The root element for a WSDL document is the definitions tag. As with any other XML document, the opening tag also takes the opportunity to define relevant namespaces that will be referenced through the rest of the document.

The namespaces commonly used in WSDL are shown in Table 9-1, along with the labels that will be consistently used throughout the examples for each. In addition to providing the namespace, the opening tag may also give a name to the service and define the target namespace that covers the service as a whole.

Table 9-1. Common namespace URIs for WSDL

Namespace URI

Label

Role

http://schemas.xmlsoap.org/wsdl/

 wsdl 

This namespace refers to the elements of the WSDL document itself.

http://schemas.xmlsoap.org/wsdl/soap/

 soap 

Elements from this namespace define the properties of binding to SOAP transport.

http://schemas.xmlsoap.org/wsdl/http/

 http 

As earlier, defining the properties of a binding to HTTP ( GET or POST ).

http://schemas.xmlsoap.org/wsdl/mime/

 mime 

MIME binding.

Various

 tns 

The tns label is generally used as a shorthand for "this namespace." It refers to the namespace covering the service itself, allowing elements like new types to be localized more easily.

In addition to these namespaces, many familiar ones, such as enc (for SOAP encoding rules), xsd (XML Schema definitions), and so on, are often present.

Using this information, the outer skeleton of the WSDL for the wish-list service would look something like the XML fragment in Example 9-2.

Example 9-2. The containing tag of the WSDL
 <?xml version="1.0"?> <definitions name="WishListCustomer"     targetNamespace="urn:WishListCustomer"     xmlns:tns="urn:WishListCustomer"     xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"     xmlns:enc="http://schemas.xmlsoap.org/soap/encoding/"     xmlns:xsd="http://www.w3.org/2001/XMLSchema"     xmlns="http://schemas.xmlsoap.org/wsdl/">     </definitions> 

The service is given the name, WishListService . This name isn't actually used in constructing calls to the server, though a client may choose to use the name in creating proxy classes for operations. To avoid confusion, the same name as the main class itself from the example code is used here.

Note that the name attribute for the definitions tag is declared in the WSDL TR document as a type called NCNAME . That is defined as a name with no colon , in essence any viable name minus any ":" character. The colon is disallowed so as to avoid confusing that part of the name with a reference to a namespace.

The other attribute the tag defined is targetNamespace . This declares what the expected namespace for messages constructed using this description will be. Note that the value given for the attribute is the same URN as defined for the tns namespace on the next line. The tns label will be used later when defining types, to qualify them into the local namespace.

9.1.2.2 Documentation, types, and messages

In most cases, the first element after definitions in a WSDL document is likely to be one of types or message . There is another element that can appear at this point. The element documentation can in fact appear inside any WSDL tags. Its content is very flexible, and its purpose is to provide human-readable documentation to accompany the entities it's placed near.

A documentation element may contain other elements, and it may also contain attributes. The declaration in the WSDL schema allows for only one restriction on attributes or contained elements: that they are properly qualified and associated with a namespace, as well as being well- formed . Using a documentation tag instead of a general XML comment has the advantage of being retrievable using XPath or a Document Object Model (DOM) representation of the WSDL.

After the optional documentation, a WSDL specification may need to provide type information beyond the basic types defined by XML Schema. This is an optional section of the document because it may not be necessary if the service uses only the preexisting types (or if the WSDL document uses the import tag to reference types from a separate file, a concept that will be discussed later in greater detail).

The types element in a WSDL file is used to contain the definitions of datatypes that are specific to the document. WSDL is defined to work with XML Schema as a means of type definition, but it isn't limited to it. The examples through the rest of the chapter will use XML Schema, however. The XML fragment in Example 9-3 shows the types block for the service being described here. It defines a type for representing the data returned on a specific book, for the data returned for books when fetching the user 's wish list, and some array constructs for cases in which the return values are sets of those types.

Example 9-3. The types section of the WishListCustomer WSDL
 <types>   <documentation>     This section defines the types that will be used by     the rest of the WSDL document to describe the data     that describes books. Only the types not already     available from XML Schema are defined here.   </documentation>   <xsd:schema targetNamespace="urn:WishListCustomer">     <xsd:complexType name="PartialBook">       <xsd:all>         <xsd:element name="isbn"   type="xsd:string"                      minOccurs="1" />         <xsd:element name="title"  type="xsd:string"                      minOccurs="1" />         <xsd:element name="url"    type="xsd:anyURI"                      minOccurs="1" />       </xsd:all>     </xsd:complexType>     <xsd:complexType name="Book">       <xsd:extension base="tns:PartialBook">         <xsd:all>           <xsd:element name="authors" type="xsd:string" />           <xsd:element name="us_price" type="xsd:string"/>         </xsd:all>       </xsd:extension>     </xsd:complexType>     <xsd:complexType name="ArrayOfPartialBook">       <xsd:complexContent>         <xsd:restriction base="enc:Array">           <xsd:attribute ref="enc:arrayType"                wsdl:arrayType="tns:PartialBook[ ]" />         </xsd:restriction>       </xsd:complexContent>     </xsd:complexType>     <xsd:complexType name="ArrayOfString">       <xsd:complexContent>         <xsd:restriction base="enc:Array">           <xsd:attribute ref="enc:arrayType"                wsdl:arrayType="xsd:string[ ]" />         </xsd:restriction>       </xsd:complexContent>     </xsd:complexType>   </xsd:schema> </types> 

Worth noting is the way PartialBook is defined. The all construct of XML Schema allows the elements to appear in arbitrary order. Were the WSDL to use sequence instead, the elements would be required to appear in the same order as the definition itself. This would require the application (or the API library, at least) to provide an extension to the serializer used by SOAP::Lite to ensure the ordering of the hash table keys. The downside of all is that the elements within are defined as appearing once or not at all. Once is fine, but these three elements are required to be present. The schema handles this by overriding the minOccurs attribute on the three elements.

In contrast, the Book structure is defined as an extension of PartialBook . It has the same three (mandatory) elements but adds two more. These are also defined in terms of the XML Schema all construct. However, they are allowed to not be present (remember, GetBook may return only the base three elements if the user calling it isn't validated ) so that operations that are typed as returning a Book value can cooperate with the authentication layer.

The WSDL specification requires that array descriptions extend the Array type from the SOAP encoding schema. Because that schema declares the arrayType attribute as being of type QName , a type that can't be given a default in schema terms, WSDL provides its own arrayType attribute that can be given an initial value. The XML Schema attribute element declares the attribute for each of the two arrays being defined, by first referencing the attribute from the SOAP encoding schema, then providing the local version with a value based on the types just defined. Here is the first place the tns namespace label is used, to qualify the PartialBook and Book types.

The message blocks can be thought of as outlining the structure of the SOAP Body blocks (see Example 9-4). They don't define every element that will eventually go into a SOAP request, but they do define the set of parts (parameters) that eventually get used in creating such requests . For the operations defined later, the input to and output from the operation will be specified in terms of the messages defined by these blocks.

Example 9-4. The message blocks for WishListCustomer
 <message name="BookRequest">   <part name="user" type="xsd:string" />   <part name="isbn" type="xsd:string" /> </message>     <message name="BookResponse">   <part name="return" type="tns:Book" /> </message>     <message name="ISBNListResponse">   <part name="return" type="tns:ArrayOfString" /> </message>     <message name="BooksByAuthorRequest">   <part name="user" type="xsd:string" />   <part name="author" type="xsd:string" /> </message>     <message name="BooksByTitleRequest">   <part name="user" type="xsd:string" />   <part name="title" type="xsd:string" /> </message>     <message name="SimpleRequest">   <part name="user" type="xsd:string" /> </message>     <message name="SimpleResponse">   <part name="return" type="xsd:anyType" /> </message>     <message name="BookListResponse">   <part name="return" type="tns:ArrayOfPartialBook" /> </message>     <message name="BooleanResponse">   <part name="result" type="xsd:boolean" /> </message>     <message name="PurchaseBooksRequest">   <part name="user" type="xsd:string" />   <part name="list" type="tns:ArrayOfString" /> </message> 

The naming of the messages is arbitrary, but in this example the messages are suffixed with either Request or Response based on which role they will be used in. Some of the responses that don't actually return data (just the object instance, such as AddBook ) are set to the special XML Schema type, anyType . This saves defining the structure of the class objects in the types section. After all, depending on whether the server is configured to return objects by reference or not, the structure of the type can be significantly different.

The message elements are built from sequences of part elements. Each part is given a name attribute and references either a type or an element , using attributes of the respective names . In the example, the schema in the types section defines only types, no elements. Had the schema declared any elements, they could be referenced by one or more of the part tags here.

All the request messages defined in the example fragment define an element in the request portion of the message named user . This element corresponds to the authentication layer that was defined for the service in the two previous chapters. Message declarations are abstract specifications, and the elements they define aren't limited to appearing just in a SOAP Body tag, for example. At this point in the sample description, SOAP isn't yet a part of the picture. There is nothing that binds specific message elements to specific transport models.

This also defines another part of the service strategy. Even though the server code can operate on an objects-by-reference basis, the WSDL is being constructed for a simple RPC-style interface. This makes for a cleaner, more easily followed example. It also means that the new and SetUser methods don't need to be exposed via the WSDL document. Operations such as AddBook or PurchaseBooks signal their success simply by not returning faults.

At this point, the emerging WSDL document has declarations for the types that are used and the structure of the input and output messages for the various operations. Defining those operations is the next step.

9.1.2.3 Operations and portType

When defining a service, related operations are grouped under an umbrella called the portType . A WSDL description isn't limited to defining only one such block, though in most simple cases, one occurrence of the portType tag is sufficient.

A portType block gathers the various operation definitions into one unit. Each operation is defined using an element called operation . Operations are named structures, and the names must be unique for each operation within a portType , just as multiple portType blocks must have unique names within their enclosing definitions block. An operation may be specified more than once, however, if the document is defining an overloaded operation. In that case, the name attributes of the input and/or output tags within the separate operations must be distinct, so that processors of the WSDL can see the differences. In these cases, the different blocks are still effectively defining just one operation . They are specifying the different signatures (to use an XML-RPC term ) the API function itself offers. Overloading will be discussed in greater detail later.

To help illustrate this, Example 9-5 shows the single portType block for the sample WSDL being built for this chapter, with some of the operation blocks contained within.

Example 9-5. The portType declaration for WishListCustomer
 <portType name="WishListCustomerPort">       <operation name="GetBook">     <input message="tns:BookRequest" />     <output message="tns:BookResponse" />   </operation>       <operation name="BooksByAuthor">     <input message="tns:BooksByAuthorRequest" />     <output message="tns:ISBNListResponse" />   </operation>       <operation name="AddBook">     <input message="tns:BookRequest" />     <output message="tns:SimpleResponse" />   </operation>       <operation name="CanPurchase">     <input message="tns:SimpleRequest" />     <output message="tns:BooleanResponse" />   </operation>     </portType> 

Not all the operation declarations are shown because they are all very similar in their structure. Because of the simple nature of this service, there is little diversity at this point.

All the operations defined in this portType block conform to what the WSDL specification calls the request-response model. The endpoint receives a request and issues a response to the data contained in the request, even if that data is limited to just the name of the operation. The WSDL specification also defines three other models: one-way , solicit-response , and notification .

Operations that follow the one-way model are those that only send a message from the client to the endpoint. The SOAP::Transport::MAILTO package provides a client class that sends messages that are treated as one-way. Likewise, the server class of the POP3 transport module also operates in a one-way model. At the other end of the spectrum, notification operations are those in which the endpoint sends a message to the client without having received any prior input, much like a RSS feed service.

The solicit-response model is similar to request-response, except that the endpoint sends a message first, and the client sends a response to that message. Both solicit-response and request-response have optional third message types in their declaration: fault .

WSDL derives the model of an operation by the types and order of the messages that are declared within the operation block. The models themselves are abstract representations that have no direct bearing on how the rest of the WSDL document is treated. Example 9-6 shows how the different models would appear. The snippets shown are adapted from the WSDL specification itself (for more information on the specification, see http://www.w3.org/TR/wsdl).

Example 9-6. Operation models in WSDL
 <portType name="examples">   <!-- One-way operation -->   <operation name="one_way">     <input message="..." />   </operation>       <!-- Notification operation -->   <operation name="notification">     <output message="..." />   </operation>       <!-- Request-response operation -->   <operation name="request_response">     <input message="..." />     <output message="..." />     <fault name="..." message="..." />   </operation>       <!-- Solicit-response operation -->   <operation name="request_response">     <output message="..." />     <input message="..." />     <fault name="..." message="..." />   </operation> </portType> 

The fault element is optional in the two-way models. It refers to a message declaration that describes the informative part of a fault, if one occurs. How this is mapped to an actual message is dependent on the transport model used in the actual binding of operations to transports. In the case of SOAP, for example, the message a fault element refers to becomes the content of the detail component of the SOAP fault construct.

The input and output elements may also have name attributes. The names must be unique within the scope of the enclosing portType tag. More accurately, all of the input and output elements do have names, but WSDL defines default values for the names to make writing WSDL documents easier. Any of these elements that don't have name attributes are assigned names based on the model and the name of the enclosing operation . Table 9-2 shows the set of rules for deriving the names based on circumstance. For one-way and notification operations, the name from the operation is applied to the input or output tag, as appropriate. For request-response and solicit-response, the operation name is appended with one of Request , Solicit , or Response , as applies.

Table 9-2. Input/output naming rules for operations

Operation model (operation name is "example")

Default input name

Default output name

One-way

Example

No output

Notification

No input

Example

Request-response

ExampleRequest

ExampleResponse

Solicit-response

ExampleResponse (see note in text)

ExampleSolicit

For the solicit-response names, remember that the input tag refers to the response that the client sends back to the endpoint, hence the name ending in Response . In the sample operation blocks in Example 9-5, all the input and output elements will fall back on these defaults.

When fault components are specified in either of the two-way models, the fault tags must have name attributes present. This is because an operation may specify more than one fault that could possibly result from the operation itself. The values of the fault name attributes are required to be unique only within the scope of the operation element, not the enclosing portType . This is different from the input and output elements.

9.1.2.4 Bindings

It's through the binding of the defined port types to actual transport specifications that services are built up. The abstractions built from the portType elements and the message elements that went into them contribute to the definition of the concrete half of WSDL that is binding and service .

The binding tag acts as a container much like the portType element from the previous section. A binding has a correlation to a portType , though it isn't limited to a one-to-one mapping; there may be multiple binding blocks that reference the same portType definition. A single binding block must define bindings for exactly one protocol, so cases in which the WSDL is expected to describe multiple access methods will have multiple bindings. A binding doesn't, however, specify address information. That is handled later, in the service declaration.

The WSDL specification provides the basis for three varieties of binding, which are shown in Table 9-3 along with the URN identifiers for their XML namespaces.

Table 9-3. WSDL binding declarations

Protocol

URN

Description

SOAP

http://schemas.xmlsoap.org/wsdl/soap/

Element and attribute definitions for binding a port to SOAP as a transport and encoding.

HTTP

http://schemas.xmlsoap.org/wsdl/http/

Elements and attributes for HTTP support, both POST and GET methods, for HTTP transport and some degree of encoding.

MIME

http://schemas.xmlsoap.org/wsdl/mime/

Elements and attributes for MIME encoding of messages, used with HTTP and/or SOAP to specify transport.

Recall from Table 9-1 that the URN given for the SOAP binding is one of the namespace declarations commonly found in WSDL documents, often labeled with the identifier soap . The other bindings are generally labeled http and mime when they are referenced in examples in the W3C specification (and also later in this chapter). The sample definitions tag in Example 9-2 has already declared the soap namespace identifier and mapped it to the appropriate URN from Table 9-3.

Returning to the task of writing the bindings for the portType defined in Example 9-5 ( WishListCustomerPort ), Example 9-7 shows the binding element and its contents for one operation, the GetBook call. Because the example is fairly simple, all the operations have the same structure in the binding block.

Example 9-7. The SOAP binding for GetBook
 <binding name="SOAP" type="tns:WishListCustomerPort">   <soap:binding style="rpc"       transport="http://schemas.xmlsoap.org/soap/http" />   <operation name="GetBook">     <soap:operation soapAction="urn:WishListCustomer" />     <input>       <soap:body use="encoded" parts="isbn"           namespace="urn:WishListCustomer"           encodingStyle=           "http://schemas.xmlsoap.org/soap/encoding/" />       <soap:header use="encoded" part="user"           message="tns:BookRequest" wsdl:required="0"           namespace="urn:WishListCustomer"           encodingStyle=           "http://schemas.xmlsoap.org/soap/encoding/" />     </input>     <output>       <soap:body use="encoded"           namespace="urn:WishListCustomer"           encodingStyle=           "http://schemas.xmlsoap.org/soap/encoding/" />     </output>   </operation> </binding> 

Starting with the opening binding tag itself, there are two attributes present: name and type . As with other places in which name occurs as an attribute, its presence here is to uniquely identify this set of bindings from others that may occur within the WSDL document. The type attribute refers back to a previously defined portType . Because there is just the one in this sample document, the relation here is pretty clear.

Immediately within the binding tag provided by the WSDL schema is the soap:binding element. This element is the first indication that the bindings being presented are going to be specifically for SOAP. There are two possible attributes for this element: style and transport . The style attribute tells whether the messages will be in rpc or document style. The differences will be discussed later, but for now know that this example uses the rpc style. This attribute is optional, but the default value is document , which isn't the desired value in this case. The transport attribute is required and points to the URI that identifies the transport by which SOAP will send and receive the messages. In this case, it indicates the HTTP transport. This is in fact the same URN that specifies HTTP as a binding model, but in this role it serves only to specify how the user should expect the actual endpoint addressing to appear.

As with the portType container element earlier, the operation tag delineates the various functions that the binding will present to clients . The name attribute of the operation tag refers specifically to an operation tag within the portType block having the same name. Just as there may have been multiple operation tags for a given function there, they can appear here, as well, if the WSDL is describing an overloaded function.

The soap:operation tag introduces the SOAP-specific information for the operation. The element allows two attributes, only one of which is used here: soapAction . If that seems familiar, it's because its role is to specify what goes into the SOAPAction header when using HTTP as a transport. It shouldn't be present if the soap:binding element didn't specify a URI indicating HTTP as the transport. The second allowable attribute in this element is the same style setting that soap:binding supports. It's only needed at this level if the specific operation wished to override the value of the earlier setting.

The critical parts of these blocks lay in the input and output tags, and the fault tags if present. These sections ultimately define what the bodies of the messages will look like. Recall the input block from Example 9-7:

 <input>   <soap:body use="encoded" parts="isbn"       namespace="urn:WishListCustomer"       encodingStyle=       "http://schemas.xmlsoap.org/soap/encoding/" />   <soap:header use="encoded" part="user"       message="tns:BookRequest" wsdl:required="0"       namespace="urn:WishListCustomer"       encodingStyle=       "http://schemas.xmlsoap.org/soap/encoding/" /> </input> 

When the abstract operation for GetBook was defined, input was declared in the form of a message called BookRequest , which specified two parts: isbn and user , referring to the ISBN of the desired book and the (optional) registered-user information. This specification for operation is stating that the isbn value will be sent within the SOAP body, while the user data will come as a header.

The soap:body element controls what eventually appears in the Body tag of the SOAP message. It's an obvious relationship, but there is a lot of information being given by this element. The part or parts attributes define which element from the message (as defined by the part tags) will be present in the body ( part may only refer to one element, parts may refer to any number, space-separated if more than one). If neither part nor parts is present, the body is assumed to contain all the parts defined in the message. The use attribute is required, and must be one of literal or encoded . A value of encoded , the most common, means that the content of the parameters is encoded according to the style given in the encodingStyle attribute, which is identical in nature to the same attribute as defined for SOAP messages. If use is set to literal , it means that the SOAP message will be constructed exactly according to the abstract definitions in the types section of the WSDL. The namespace attribute provides the target namespace for the Body itself.

The use of soap:header is a little bit different. It also understands the use , namespace , and encodingStyle attributes as they apply to soap:body . The part attribute has the same role but is required in this case. It also requires a message attribute that names the abstract message definition it's using, in which the element from part must exist. If the header is declared with use set to literal , the schema definition for the element that part specifies may include definitions for the soap:actor and soap:mustUnderstand attributes. If use is set to encoded , these aren't permitted. A soap:header may refer to a part from a different message than the soap:body element refers to. Because the user-authentication information isn't explicitly required by the GetBook operation, this header uses the required attribute from WSDL to tell any application reading the description that the header may not be present. When required is set to a true value, the element must be present in the message. The soap:body element, for example, has an implied wsdl:required value of true (or 1 ) because the SOAP specification requires that the Body tag be present.

The relationship between soap:body and soap:header is very close. Between the name attributes of the operation and input (or output ) tags, the exact message specification is chosen from the portType . That abstract specification details the parts that are supposed to be present in the body, and the parts are divided between the soap:body and any soap:header elements declared. In some cases, a multipart MIME encoding may lead to some parts appearing in different places within the whole message, rather than having them all enclosed within the Body tag of a SOAP message. The same default naming rules for the input and output tags apply to the binding sections as to the portType section.

Faults are handled in the specification of bindings using the soap:fault element, or soap:headerfault element for faults that occur in headers. The examples given earlier did not include these definitions because these tags provide the structure of the detail element of the SOAP Fault structure, and the example application's faults only use the faultcode and faultstring elements. The soap:fault element uses the same name , use , encodingStyle , and namespace attributes that have been defined earlier. Because the fault declaration in portType is required to have a name , so is soap:fault . The value of name refers back to the name of the corresponding fault from the portType block. Faults are declared outside of input or output tags.

The soap:headerfault specification is given within a soap:header element to signify a possible fault at the header level. It uses the same attributes as soap:header does, including the mandatory name and message attributes. As with soap:header , it may refer to a part in a message different from the one on which the soap:body tag is based.

9.1.2.5 Service definitions

The last part of the WSDL puzzle is the service element, which defines the actual service as it's to be presented to clients. In contrast to the complexity that can creep into the binding declarations, the service block is generally very simple. The block for the sample specification is shown in Example 9-8.

Example 9-8. The service block for WishListCustomer
 <service name="WishListCustomer">   <port name="WishListCustomerPort" binding="tns:SOAP">     <soap:address location="http://localhost:9000" />   </port> </service> 

The service tag has only one attribute and one possible child element. The name attribute gives the service a unique name (among other service blocks). Naming allows for several services to be defined by one WSDL document.

The only child element of service is port , which has two attributes but no child elements defined within the WSDL schema. The attributes that are permitted are name and binding . The function of name should be clear, and the value must be unique within the enclosing service tag. The binding attribute refers to a binding block defined elsewhere in the WSDL document. In the case of this example, there is only the one binding defined, named SOAP . A WSDL specification can define multiple bindings, and in turn a service can define multiple port elements. If there are multiple ports, there are three rules from the W3C specification to keep in mind:

  • Ports don't communicate with each other. One port's output can't be specified as another port's input.

  • When a service has multiple ports that share the same port type but use different bindings, this is intended to present alternatives, allowing clients to select which port to communicate with, based on whatever criteria they choose, such as protocol, etc.

  • Examining a service's ports illustrates the port types the server offers. The extension elements within the port tags provide a relationship back to a specific type of binding, thereby informing potential clients.

Because the WSDL schema defines no child elements for port, the only elements that can appear there come from the SOAP, HTTP, or MIME extensions (or any future extensions that may be developed). In Example 9-8, the soap:address element provides the URI clients use to contact the server. In keeping with the transport attribute of the soap:binding tag earlier, the URI refers to an HTTP endpoint. The URI is provided by the attribute called location .

The final version of the WSDL is listed in Appendix E. With annotation in the form of numerous documentation elements, the file is in excess of 400 lines.

9.1.3 HTTP and MIME Binding in WSDL

Thus far, the WSDL sample document has focused on the SOAP binding methodology. But the WSDL specification defines two other binding methods, HTTP and MIME. These can work together, separately, or with the SOAP bindings previously described.

9.1.3.1 Extending WSDL with HTTP

The HTTP bindings for WSDL aren't very different in structure or meaning from the SOAP bindings. The most significant difference is the need to specify which operation (or verb , in HTTP terminology) will perform the operation, and how the arguments are to be transformed into the HTTP request.

Unlike SOAP, there's little inherent structure to HTTP requests. Whether using POST or GET , the basic model of requests is to provide the parameters as sequences of name = value pairs. The specific syntax and encoding of the data is determined by the verb, but there is little else that differs . Expressing complex data is difficult due to the flat nature of the encoding.

The HTTP binding extensions for WSDL consist of the five elements described in Table 9-4. Refer back to Table 9-3 for the namespace URN that references the binding schema. In most published examples, the URN is assigned to the label http .

Table 9-4. HTTP binding elements

Element

Role

http:address

Used in the service element, this provides the physical address for the service as a URL in an attribute called location . Similar to the soap:address element.

http:binding

This is used in the binding element, to specify that the binding will be based on the HTTP layer. It has one attribute, verb , that is one of GET or POST . The attribute is required.

http:operation

Operations for the HTTP binding are specified by providing a relative URI within this element, as a value for an attribute called location . The URI must be relative because it's appended to the URI in http:address .

http:urlEncodedhttp:(urlReplacement)

One of these two is present in the input element when the http:binding element specifies GET as the value of verb . They indicate how the values being passed are to be transformed into parts of the HTTP request line.

The WSDL fragment in Example 9-9 shows practical application of the HTTP extension elements to the binding and service elements of the WSDL description that has been the running example this chapter.

Example 9-9. HTTP binding, first draft
 <binding name="HTTP" type="tns:WishListCustomerPort">   <http:binding verb="GET">   <operation name="GetBook">     <http:operation location="GetBook" />     <input>       <http:urlEncoded />     </input>     <output>       <mime:mimeXml part="return" />     </output>   </operation> </binding>     <service name="WishListCustomer">   <port name="WishListCustomerHTTP" binding="tns:HTTP">     <http:address location="http://localhost:9001" />   </port> </service> 

In this example, the http:urlEncoded tag is used in the input element. This tells the client that requests to the service should have their input parameters encoded into the URL using the standard rules for parameter encoding. Because the GetBook operation uses parameters named user and isbn , this looks like (with the full URL):

 http://localhost:9001/GetBook?user=...&isbn=... 

Note how the URL itself is built by concatenating the location values from the http:address and http:operation elements. The values of the parameters must also be encoded, in order to escape characters , such as spaces, ampersands, and percent signs.

Another thing to note is that the output is built using the MIME extension elements, described later. The HTTP extensions don't describe any output encoding methods. Instead, output is described using either the SOAP encoding elements from the SOAP extension or the MIME elements as in this example. HTTP and MIME are often used together in this context.

Example 9-10 shows a second draft of the same operation under an HTTP binding. Only the operation section is shown to illustrate the way http:urlReplacement works.

Example 9-10. HTTP binding, second draft
 <operation name="GetBook">   <http:operation location="GetBook/(user)/isbn=(isbn)" />   <input>     <http:urlReplacement />   </input>   <output>     <mime:mimeXml part="return" />   </output> </operation> 

When using the http:urlReplacement method, the value of the location attribute is examined for patterns that match an input part name within parentheses. In the case of GetBook , the parts are simple. The user element is meant to be inserted between two slashes , with no other labeling. This can imply that another mechanism, such as the Apache web server's request lifecycle-based authentication, may be handling that part of the process. The isbn parameter is encoded with a label, similar to URL encoding. Using this approach gives a greater degree of control over the format and placement of the parameters to the call.

When http:urlReplacement is performed, it's performed only against the location part of the corresponding http:operation tag. It happens before this value is appended to the location part of the soap:address . All matching is done before any values are substituted, so content in a value being pasted in can't trigger a later match.

When using the POST verb for HTTP, URL encoding is no longer an issue, but content-encoding becomes an issue instead. Fortunately, encoding of parameters for POST requests is quite standard, with a well-defined MIME content type. Example 9-11 shows the third draft of the HTTP binding, this time centered around POST .

Example 9-11. HTTP binding, third draft
 <binding name="HTTP" type="tns:WishListCustomerPort">   <http:binding verb="POST">   <operation name="GetBook">     <http:operation location="GetBook" />     <input>       <mime:content           type="application/x-www-form-urlencoded" />     </input>     <output>       <mime:mimeXml part="return" />     </output>   </operation> </binding> 

This again shows the close relationship between the HTTP and MIME extensions.

9.1.3.2 Using the MIME extension elements

In the case of the HTTP bindings, it was shown that the extension didn't provide any elements for expressing output, relying instead on the MIME or SOAP extensions to handle that. Likewise, the MIME extensions don't define any elements for the transport elements of bindings, only for describing content. The MIME extension elements are described in Table 9-5. Refer to Table 9-3 for the namespace URN that is used to reference these extensions.

Table 9-5. The MIME extension elements for bindings

Element

Role

mime:content

This element is provided in order to avoid defining a new element for every MIME format. When the only information that needs to be conveyed is the content type (and possibly the part name), this element may be used with the attributes type and part , respectively.

mime:multipartRelated

mime:part

These elements work together to specify data as a collection of related MIME parts. The first element declares the content as being of the multipart/related MIME content-type , while the mime:part elements define the individual parts.

mime:mimeXml

To define a message part that is XML but isn't a compliant SOAP message (doesn't conform to the SOAP schema), use this element. It has one attribute, part , that refers to a message component. The content for this part of the message will be the data, serialized but not fully SOAP-encoded.

In addition to the typing rules defined in Table 9-5, when using the MIME extensions with the SOAP extensions, a soap:body element may be specified as a content element. It's equivalent to specifying a mime:content element in which the type attribute is text/xml and the content is expected to be contained within a SOAP envelope.

Example 9-12 illustrates how the different elements of the MIME extension work together. Because the operations from the sample WSDL don't exercise the full flexibility MIME offers, this example isn't related to the previous ones.

Example 9-12. Simple MIME extensions demonstration
 <definitions name="MIMEsample"     targetNamespace="urn:MimeSample"     xmlns="http://schemas.xmlsoap.org/wsdl/"     xmlns:tns="urn:MimeSample"     xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"     xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"     xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"     xmlns:xsd="http://www.w3.org/2001/XMLSchema">       <message name="in">     <part name="fractal" type="xsd:string" />     <part name="xrange" type="tns:float-range" />     <part name="yrange" type="tns:float-range" />     <part name="resolution" type="tns:resolution" />   </message>   <message name="out">     <part name="return" type="xsd:binary" />     <part name="graph" type="tns:graph-detail" />   </message>       <portType name="GenerateFractal">     <operation name="MakeFractal">       <input message="in" />       <output message="out" />     </operation>   </portType>       <binding name="fractal" type="tns:GenerateFractal">     <soap:operation soapAction="urn:MakeFractal" />     <input>       <soap:body use="literal" />     </input>     <output>  <mime:multipartRelated>   <mime:part>   <mime:content part="return" type="image/png" />   </mime:part>   <mime:part>   <soap:body part="graph" use="literal" />   </mime:part>   </mime:multipartRelated>  </output>   </binding>       <service name="FractalMaker">     <port name="FractalPort" binding="fractal">       <soap:address location="http://fractal.com/SOAP" />     </port>   </service> </definitions> 

While a much longer example, it shows the MIME extensions working side by side with the SOAP extension elements. The WSDL describes a hypothetical fractal calculation engine, in which the input is a SOAP message with information such as the type of fractal to compute, the ranges of calculation on some of the axes, and the resolution of the desired image to return. Rather than try to manage the image into a SOAP data element, the return model uses MIME multipart/related to handle the data that gets sent back to the client. The highlighted section shows how the image is specified using mime:content with a type of image/png . Following that part of the message, the graph element, presumably an XML structure describing the specifics of the fractal space being modeled , is returned as a soap:body content element. The end result is that the graph portion of the message comes across in an easily parsed SOAP envelope, while the image comes in a separate MIME container.

9.1.4 Overloading Operations in WSDL

The overloading of operations is a delicate subject within web-services discussion circles. Different people have different points of view, placing varying support or importance on the concept and its useful application to web services in general, and WSDL in particular. Regardless, it's available using the syntax WSDL provides, and thus may prove a useful addition to the web-services toolbox.

Specifying an overloaded operation requires coordinated definitions in both the declaration of the abstract operations and the binding of the abstract messages to concrete communication models.

9.1.4.1 Overloading when declaring operations

To demonstrate how to express overloaded operations in WSDL, the examples will leave the WishListCustomer application briefly , going back to the use.perl.org journal system ”specifically, to the add_entry operation defined in that interface.

For the sake of the example, we will alter the interface slightly. As written, the interface doesn't suit itself to WSDL expression. The add_entry call may be called in one of two ways:

  • Exactly two arguments, the journal entry subject and body, respectively.

  • A list of key/value pairs, with up to five pairs. The allowed keys are subject , body , posttype , discuss, and tid .

The second calling convention doesn't impose an order on the arguments, which is a problem to represent in WSDL. To accommodate this, the second convention is changed to a single array-of-string type. Example 9-13 shows the first part of the WSDL, the opening definitions tag, the single type-declaration for the array, and the messages the operation will need.

Example 9-13. Initial elements of the WSDL for add_entry
 <definitions name="UsePerlJournal"     targetNamespace="http://use.perl.org/Slash/Journal/SOAP"     xmlns="http://schemas.xmlsoap.org/wsdl/"     xmlns:tns="http://use.perl.org/Slash/Journal/SOAP"     xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"     xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"     xmlns:enc="http://schemas.xmlsoap.org/soap/encoding/"     xmlns:xsd="http://www.w3.org/2001/XMLSchema">   <types>     <xsd:schema targetNamespace=                 "http://use.perl.org/Slash/Journal/SOAP">       <xsd:complexType name="ArrayOfString">         <xsd:complexContent>           <xsd:restriction base="enc:Array">             <xsd:attribute ref="enc:arrayType"                  wsdl:arrayType="xsd:string[ ]" />           </xsd:restriction>         </xsd:complexContent>       </xsd:complexType>     </xsd:schema>   </types>   <message name="TwoElementInput">     <part name="subject" type="xsd:string" />     <part name="body" type="xsd:string" />   </message>   <message name="ListInput">     <part name="list" type="tns:ArrayOfString" />   </message>   <message name="AddEntryResult">     <part name="return" type="xsd:int" />   </message> 

Thus far, there is nothing different about this WSDL than was seen in the previous examples. The difference becomes visible in Example 9-14, when the portType is defined for the journal system.

Example 9-14. The portType declaration for the journal
 <portType name="UsePerlJournalPort">   <operation name="add_entry">     <input name="TwoElementCall"            message="tns:TwoElementInput" />     <output name="TwoElementReturn"             message="tns:AddEntryResult" />   </operation>   <operation name="add_entry">     <input name="ListCall" message="tns:ListInput" />     <output name="ListReturn"             message="tns:AddEntryResult" />   </operation> </portType> 

In this block, the operation element appears twice, both times naming add_entry as the operation being defined. The blocks differ in their nature from the previous examples in that the input and output elements are given explicit names, rather than relying on the defaults. Because the return types are identical for both calls, naming the output part isn't necessary but is done to avoid confusion. The combinations of operation name and input/output names uniquely identify the ways in which add_entry may be called.

9.1.4.2 Implementing overloaded operations within bindings

With the abstract definitions in place, the responsibility for exposing the multiinterface add_entry call falls to the binding and service elements. These are shown in Example 9-15.

Example 9-15. The binding and service elements for add_entry
 <binding name="UsePerlJournalSOAP"          type="tns:UsePerlJournalPort">   <soap:binding style="rpc"                 transport=                 "http://schemas.xmlsoap.org/soap/http" />   <operation name="add_entry">     <soap:operation         soapAction=         "http://use.perl.org/Slash/Journal/SOAP" />     <input name="TwoElementCall">       <soap:body use="encoded"           namespace=           "http://use.perl.org/Slash/Journal/SOAP"           encodingStyle=           "http://schemas.xmlsoap.org/soap/encoding/" />     </input>     <output name="TwoElementResult">       <soap:body use="encoded"           namespace=           "http://use.perl.org/Slash/Journal/SOAP"           encodingStyle=           "http://schemas.xmlsoap.org/soap/encoding/" />     </output>   </operation>   <operation name="add_entry">     <soap:operation         soapAction=         "http://use.perl.org/Slash/Journal/SOAP" />     <input name="ListCall">       <soap:body use="encoded"           namespace=           "http://use.perl.org/Slash/Journal/SOAP"           encodingStyle=           "http://schemas.xmlsoap.org/soap/encoding/" />     </input>     <output name="ListResult">       <soap:body use="encoded"           namespace=           "http://use.perl.org/Slash/Journal/SOAP"           encodingStyle=           "http://schemas.xmlsoap.org/soap/encoding/" />     </output>   </operation> </binding> <service name="UsePerlJournal">   <port name="UsePerlJournalPort"         binding="tns:UsePerlJournalSOAP">     <soap:address location=                   "http://use.perl.org/soap.pl" />   </port> </service> 

Aside from the specific naming of the input and output elements, these bindings look like the previous examples. But the presence of the names tells the client using this WSDL which of the two abstract models should be paired with the actual operational binding. Fortunately, the rest of the specification for the operations is standard. However, if there was a need to break parts up between soap:body and soap:header elements, or through parts in the MIME extension elements, it would be more important for an application processing the WSDL to know exactly which parts were expected to be present.

These examples have addressed only one part of the use.perl.org interface because that was all that was relevant to the concepts here. To be thorough, a full WSDL description (with documentation elements) is provided in Appendix E, along with the WSDL from the previous examples. Note that the WSDL doesn't address the cookie-based authentication means that the journal interface uses. Neither the SOAP nor the HTTP extension elements to WSDL provide a way to describe HTTP cookie content in messages.

9.1.4.3 Why bother with overloading in Perl?

While these examples show how to express overloaded operations in WSDL, the question still remains as to why this should be needed when Perl is so flexible and accommodating in what it can accept in a parameter list.

The answer lies in the fact that the goal of web services is to avoid any language-specific dependencies or issues. Even if a service is written in Perl, it's a plain fact that it will likely be accessed by languages other than Perl. The sample script from Chapter 6, which posted journal entries to use.perl.org , sprang from a comment about writing such a utility directly in Emacs Lisp. The Perl solution was designed as a filter ”less to promote Perl than to prevent coupling the solution to just Emacs.

Not all languages have the luxury of subroutines that can examine their argument lists in the fashion Perl can. Conversely, a common oversight in developing Perl clients to connect to non-Perl services is to overlook matters such as the naming and formal typing of parameters to service calls. It's in bridging these gaps that WSDL truly proves its worth.

9.1.5 Other WSDL Elements

The examples built through the course of the last few sections didn't cover all the elements and bindings offered by WSDL. There are attributes that provide hints related to parameter order within RPC-like calls, and there is the issue of document-style message encoding, as opposed to RPC. There is also the support for modular document development with the import element of WSDL.

9.1.5.1 Controlling arguments with parameterOrder

When creating bindings for rpc -style encoded messages, it's possible to define the order in which the parameters will appear in the message. The attribute called parameterOrder specifies a list of one or more parameter names ( part elements from the message definitions), separated by spaces. It's present in the operation tag, and serves as a hint only. It can be safely ignored by readers of the WSDL who aren't concerned with RPC signatures.

When the parameterOrder attribute is used, it follows a certain set of rules, according to the W3C WSDL specification:

  • The parts order in the attribute reflects the signature of the RPC operation.

  • The return parameter for the output block isn't included in the list. Its presence is already assumed.

  • Parts in the list that appear in both the input and output blocks are considered in/out parameters .

  • Parts that appear only in the input block are in parameters , while those that appear only in the output block are out parameters .

The parameterOrder attribute has no affect on non-RPC document styles.

9.1.5.2 Document-style message encoding

In the example WSDL, the soap:binding element included an attribute called style , which was set to the value rpc . The default style under WSDL is called document . When an operation is describing document -style messages, the name of the operation doesn't get incorporated into the resulting message body, as it does with the rpc style.

The document style is meant to indicate that the operation is sending and receiving full documents that have no further need for manipulation. In the case of rpc messages, the assumption is that the message describes the parameters of an operation. To indicate this, the message body is made up using the operation name as a containing element. In all the examples so far, the RPC style has been the norm.

The message elements used in document -style operation blocks describe the actual message bodies themselves, completely. No additional wrapping is done. The role of the use attribute becomes more important in document -styled messages. Message parts that reference elements instead of a schema type have the element wrapping the data, acting as a child of the containing element ( Body when the use attribute applies to the soap:body tag, and so forth).

9.1.5.3 Modular WSDL with the import element

One feature of WSDL not yet addressed is the ability to use external sources from within a WSDL specification through the import element.

The import element in WSDL establishes a link between a location and a namespace. Whether or not the processing of import results in the loading of the additional document is dependent on the application. What is required is that the elements and types from the referenced file are available via the namespace used.

A common use of import is to allow the XML Schema declarations of types to be kept in a separate file, usable by other schema-driven application besides WSDL. Imagine that the XML Schema declarations from Example 9-3 were kept in a file called wishlisttypes.xsd , the URI for which was based on the service address: http://localhost:9000/wishlisttypes.xsd . In place of the types tag in the sample WSDL, the following line can provide access to the type declarations through the rest of the WSDL description:

 <import namespace="urn:WishListCustomer"     location="http://localhost:9000/wishlisttypes.xsd" /> 

The value of the namespace attribute in this case is the namespace that covers the description itself. Another namespace can be used, providing there's a way to use it when referencing the types (the label tns has already been set up for the namespace).

The import element may be used multiple times, to pull in definitions from different files or even to associate the same set of definitions with multiple namespaces. It isn't unusual to see a document use import in place of the types element.



Programming Web Services with Perl
Programming Web Services with Perl
ISBN: 0596002068
EAN: 2147483647
Year: 2000
Pages: 123

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net