Documenting Your Web Service
July 24, 2001
If you read our last column, you are probably expecting an article on interoperability. As it turns out, lately I have been thinking more about documentation than about interoperability, so in this article we are going to look at how to document a Web Service. (This also buys me some time to create some good examples running on non-Microsoft toolkits. It should be worth the wait.)
Documentation for a Web Service needs to contain several different elements. First and foremost, it should provide a Web Services Description Language (WSDL) file that programmatically describes the Web Service. Secondly, it needs to provide written documentation describing how to use the Web Service. This should include various items, including an API reference, troubleshooting tips, and usage descriptions. Finally, the documentation should provide sample code for all of the operations, preferably using the fewest lines of code needed to call the given method. Examples of SOAP messages going back and forth should be included along with the code. These sample messages will help developers develop a client in languages other than those outlined by the samples. Ideally, the documentation also should include a sample client that uses the Web Service, complete with source code.
In this column, we will examine why this information is needed and explain its value. A lot of the Web Services available today at sites such as XMethods have simple interfaces that return information like the current temperature based on zip code. Future, commercial Web Services, however, will have richer and more complex interfaces; they will need documentation to describe their use.
When documenting a Web Service, you must provide a WSDL document. This document provides critical information about the Web Service that both the developers and programming tools need. In a compact, concrete way, this document describes everything, including:
- Messages that the Web Service understands and the format of its responses to those messages
- Protocols that the service supports
- Where to send messages
All of this information combines to give the programmer a view of how the system expects outside applications to interact with the Web Service. Thus, the WSDL is the main piece of documentation your users need.
Remember, examples and expanded documentation are always needed for non-trivial Web Services. Without examples and expanded documentation, developers programming against the Web Service may not use the service as you intend, or may run into problems and give up in frustration.
A WSDL document always has a definitions element as its root. The elements in the document specific to WSDL all belong to the WSDL namespace, the URI of which is http://schemas.xmlsoap.org/wsdl/. Any WSDL language element can contain another element named document. This element contains human-readable text and is meant to document the containing element. The document element can contain arbitrary text and elements. The WSDL-specific elements are:
- types: Describes the types used by messages
- message: Defines the data passed from one point to another in a call
- portType: Defines a collection of operations
- operation: Defines a combination of input, output, and fault messages
- input: A message that is sent to the server
- output: A message that is sent to the client
- fault: An error value returned as a result of a problem processing a message
- binding: Describes the protocol being used to carry the Web Service communication; bindings currently exist for SOAP, HTTP GET, HTTP POST, and MIME
- service: Defines a collection of ports; each service should map to one portType and represent different ways of accessing the operations in that portType
Many of these elements may also contain extensibility elements. Extensibility elements define how various features of a given transport can be mapped to that particular element. For example, within an operation element for a SOAP binding, you can specify the SOAPAction and the style of communication (RPC or document).
This section will give a brief overview of the various items provided by a WSDL file. For full coverage, consult the WSDL specification, located at Web Services Description Language (WSDL) 1.1.
WSDL documents can define the types used by the messages. When defining custom types, you should use XSD instead of other type-definition languages. Using XSD allows you to more easily interoperate with other WSDL-aware toolkits. This also helps those who may have to generate custom clients by hand. If, however, you see a need to define your own type system, you may—but I don’t recommend it.
The types show up in a types block. Using this, you can map your own language-specific, custom types to an XSD representation. If a baseball team wanted to return a player with their name, batting average, year of the batting average, and the player’s number, they could do so with the following type definition:
<types> <s:complexType name="Player"> <s:sequence> <s:element minOccurs="1" maxOccurs="1" name="Name" nillable="true" type="s:string" /> <s:element minOccurs="1" maxOccurs="1" name="Average" type="s:double" /> <s:element minOccurs="1" maxOccurs="1" name="Year" type="s:long" /> <s:element minOccurs="1" maxOccurs="1" name="Number" type="s:short" /> </s:sequence> </s:complexType> </types>
This section uses a few XML namespaces that were defined elsewhere in the document. The important thing to note here is that we have names for a set of elements that define a player. The complex type, Player, is now defined and can be mapped to many different languages. This type also specifies how we serialize a Player to and from the wire. If used in a message, this element would then look like this:
<message name="PlayerMessage"> <part name="thePlayer" element="s0:Player" /> </message>
portTypes and Bindings
The WSDL can also document the operations on a given portType as well as any binding-specific data. Related operations should exist within a given portType. The relationship of these operations is typically defined by the piece of code that implements them. For example, if a COM object or Java class exposes 5 methods as Web Services, those 5 methods combine to define the portType. Each portType then has a matching binding element. The binding element can be used to define how each operation within the portType maps to a particular protocol. You may have a portType with the following definition:
<portType name="PlayerStats"> <operation name="GetBattingAverage"> <input message="s0:GetBattingAverageIn" /> <output message="s0:GetBattingAverageOut" /> </operation> </portType>
This portType may be supported by several methods (recall that a Web Service can be accessed over several protocols including SOAP, HTTP GET, and HTTP POST). A binding to SOAP might look like this:
<binding name="PlayerStatsSoap" type="s0:PlayerStats"> <soap:binding transport=http://schemas.xmlsoap.org/soap/http style="document" /> <operation name="GetBattingAverage"> <soap:operation soapAction="http://www.seattlemariners.org/GetBattingAverage" style="document" /> <input> <soap:body use="literal" /> </input> <output> <soap:body use="literal" /> </output> </operation> </binding>
This binding element states that the operations will travel using SOAP over HTTP. The GetBattingAverage operation uses the HTTP SOAPAction header, http://www.seattlemariners.org/GetBattingAverage. The operation is document oriented and uses literal encoding.
We can also define where the particular service endpoint is located. If the endpoint is reachable over a few different bindings, such as SOAP, HTTP GET, and HTTP POST, the service section may look like this:
<service name="PlayerStats"> <documentation>Gets player information for the Seattle Mariners.</documentation> <port name="PlayerStatsSoap" binding="s0:PlayerStatsSoap"> <soap:address location="http://someIP/baseball1/baseballservice.asmx" /> </port> <port name="PlayerStatsHttpGet" binding="s0:PlayerStatsHttpGet"> <http:address location="http://someIP/baseball1/baseballservice.asmx" /> </port> <port name="PlayerStatsHttpPost" binding="s0:PlayerStatsHttpPost"> <http:address location="http://someIP/baseball1/baseballservice.asmx" /> </port> </service>
This particular service description indicates that the same endpoint, http://someIP/baseball1/baseballservice.asmx, can handle all three bindings. You could also use this section to describe several identical endpoints at different locations.
<service name="PlayerStats"> <port name="PlayerStatsUSA" binding="s0:PlayerStatsSoap"> <soap:address location= "http://someIPInUSA/baseball1/baseballservice.asmx" /> </port> <port name="PlayerStatsJapan" binding="s0:PlayerStatsSoap"> <soap:address location= "http://someIPInJapan/baseball1/baseballservice.asmx" /> </port> </service>
The documentation for your Web Service should also describe how you expect people to use your Web Service. Explain how errors will be returned, how to initiate usage, and so on. This information will help get others up and running with your Web Service. Unless you are doing something simple, like retrieving a stock quote based on ticker symbol, people are going to need good documentation.
First, include an overview document. A good overview contains pointers to and summaries of the documentation relating to the Web Service—WSDL locations, developer guides, API reference, and so on. Within the developer guide, explain how the Web Service is to be used. Describe typical usage scenarios, as well as error handling.
When describing error handling, list errors that can be returned for each and every Web Service method. Give the return codes, so that client developers can look up the error number, as well display a meaningful message to their end users in either a display message or a log entry. For the Favorites Service, we have a section of documentation explaining how to handle errors; it also gives a short overview of how to handle SOAP faults in general. We then indicate how to find the error code and the error description. We follow this up in the method descriptions by providing a table indicating what errors exist and what the numeric values mean. For example, we document that the GetFavorites call can return the following errors:
|1002||Invalid licensee key.|
|1005||Invalid user name.|
Instead of listing the errors on a method-by-method basis, you could also make a list of all errors that all Web Services might return. The difficulty with this, however, is that client developers will not know what errors can be returned by the various pieces of code. This makes writing error-handling code harder for them, but does make your documentation easier to create and maintain. We decided that we would be better off doing the hard work, instead of having the developer learn through trial and error the errors they had to handle. This follows the model used by most of the Windows API documentation, where each function documents errors it might return.
Besides error handling, you will also want to document the various operations in the Web Service. This should look like any other API documentation:
- Explain what the operation does
- Define the meaning and type of the parameters of the operation
- Provide sample code
- Give helpful hints
In addition to the above, give a sample SOAP message exchange-dependent upon the communication pattern used (one-way, request-response, and so on.
You will also want to spend a little time defining the object or, in WSDL parlance, portType. That is, describe the collection of functions and give a pointer to where the user can find the WSDL file. Client developers will want the WSDL file, so that they can use WSDL-aware libraries to call your Web Service.
Finally, take some time to develop a sample client that uses most, if not all, of the operations exposed by the Web Service. Make sure that the sample actually looks like something you expect a client developer might want to build. This reference may prove to be more useful than you think—the developer can use the sample to verify if the problem is in their implementation or somewhere with the Web Service itself.
In order for your Web Service to be successful, documentation is critical. You will need to provide more than just an endpoint that talks SOAP. Describe the Web Service using a WSDL document. Client developers can then take advantage of the many proxy libraries and use the endpoint without crafting the needed XML and HTTP headers. The WSDL also helps developers when things go wrong by letting them know how the messages are constructed. At this point, they need to extend their knowledge of SOAP. The WSDL gives them a roadmap to explain what they should be seeing in the communications between their machine and yours.
Explain to client developers what errors the various operations can return. This will help them write good error-handling code, because they will know what to expect. If you fail to lay this out, developers either have overkill to handle the errors, which wastes their time, or they handle no errors. Handling no errors leads to dissatisfaction with the Web Service, and this dissatisfaction will lead to your Web Service not being used.
Finally, document how to use each operation, and give samples on how to call the various operations. Describe this in detail, and give information on diagnosing common problems. Also, document any calling dependencies. For example, most of the operations in the Favorites Service take a key that the caller gets by first logging in. If you have other dependencies, you will need to make those dependencies known. By following these recommendations, you will make it much easier for others to use your work.
For our next column, a guest will write about the upcoming Project Lucy.
At Your Service
Scott Seely is a member of the MSDN Architectural Samples team. Besides his work there, he has published two books through Prentice Hall: SOAP: Cross Platform Web Service Development Using XML and Windows Shell Programming. He wrote and maintains a small C++ based SOAP library (http://www.scottseely.com/soap.htm), published under the LGPL.