This article may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist. To maintain the flow of the article, we've left these URLs in the text, but disabled the links.


MIND

This article assumes you're familiar with COM, XML, JScript
Download the code (9KB)
SOAP: The Simple Object Access Protocol
Aaron Skonnard

Remote objects can give a program almost unlimited power over the Internet, but most firewalls block non-HTTP requests. SOAP, an XML-based protocol, gets around this limitation to provide intraprocess communication across machines.

Developers have a hard time agreeing on anything. They are fiercely loyal to the technologies they use and they don't like to compromise by adding support for the other guy's technology. Long and bitter technical wars have ensued, leaving interoperability the victim. See Don Box's recent article, "Lessons from the Component Wars: An XML Manifesto" (http://msdn.microsoft.com/workshop/xml/articles/xmlmanifesto.asp) for another perspective on the problem.
      For the most part, software component developers from opposite sides of the tracks stay as far away from each other's technology as possible. This polarity makes it difficult to achieve any level of interoperability. It would be great to find a component technology standard that everyone could agree on. It could be that a subset of minimal technologies is the best answer to this quandary.
      XML and HTTP are two such minimal technologies. The Simple Object Access Protocol (SOAP) defines the use of XML and HTTP to access services, objects, and servers in a platform-independent manner. SOAP is a protocol that acts as the glue between heterogeneous software components. If developer can agree on HTTP and XML, SOAP offers a mechanism for bridging competing technologies in a standard way. The main goal of SOAP is to facilitate interoperability.
      The industry has accepted HTTP. It's used everywhere, on all platforms. XML is becoming as ubiquitous as HTTP. Today you can find an XML processor for just about any common platform or language. This ubiquity makes HTTP a good choice for an interoperable transport mechanism.
      XML is a simple and extensible text markup language. Because XML is just text, any application can understand it as long as the app understands the character encoding in use. By default, XML assumes that all characters belong to ISO/IEC 10646, known as the Universal Character Set (UCS). The XML specification (http://www.w3.org/XML/) mandates that all XML processors must accept character data encoded using the UCS Transformation Formats UTF-8 or UTF-16. Therefore, any XML data stream encoded in UTF-8 or UTF-16 can be understood regardless of platform or programming language. (Note that since the first 256 character codes of UTF-8 match up with ASCII, a UTF-8-capable processor can understand straight ASCII text files. This makes XML a good choice for describing method invocations in a platform and language-neutral fashion.
      Combining HTTP and XML into a single solution gives you a whole new level of interoperability. For example, lathered with SOAP, clients written in Microsoft® Visual Basic® can easily invoke CORBA services running on UNIX boxes, JavaScript clients can easily invoke code running on the mainframe, and Macintosh clients can start invoking Perl objects running on Linux. The list goes on. While some interoperability is achieved today through cross-platform bridges for specific technologies, once SOAP becomes standard, bridges will no longer be necessary.
      As you'll see, much of what SOAP represents is simple, and it's nothing new. SOAP simply codifies existing practices into an industry standard from which everyone can benefit.

Firewall Woes
      Currently, developers struggle to make their distributed applications work across the Internet when firewalls get in the way. Since most firewalls block all but a few ports, such as the standard HTTP port 80, all of today's distributed object protocols like DCOM suffer because they rely on dynamically assigned ports for remote method invocations. If you can persuade your system administrator to open a range of ports through the firewall, you may be able to get around this problem as long as the ports used by the distributed object protocol are included.
      To make matters worse, clients of your distributed application that lie behind another corporate firewall suffer the same problems. If they don't configure their firewall to open the same port, they won't be able to use your application. Making clients reconfigure their firewalls to accomodate your application is just not practical.
      Since SOAP relies on HTTP as the transport mechanism, and most firewalls allow HTTP to pass through, you'll have no problem invoking SOAP endpoints from either side of a firewall. Don't forget that SOAP makes it possible for system administrators to configure firewalls to selectively block out SOAP requests using SOAP-specific HTTP headers.

SOAP-like Technologies
      DCOM-savvy developers will recognize that SOAP is similar to COM Internet Services (CIS). CIS makes it possible to use DCOM in concert with HTTP (on port 80). CIS uses a special HTTP-based handshake to establish the initial connection between the client and server. From that point on, CIS relies on DCOM over TCP. While CIS does solve the firewall problem, it's a platform-specific solution. CIS only works on certain Windows®-based systems with the appropriate CIS infrastructure in place (such as Internet Information Service (IIS), a special ISAPI DLL, and special DCOM configuration settings). CIS makes no attempt to improve interoperability over the Internet.
      SOAP is also similar to the Remote Data Services (RDS) DataSpace object, which makes it possible to instantiate custom business objects on remote servers over HTTP. The following Visual Basic code illustrates how to create the Lib.BusinessObj object on the server identified by http://skonnard.com:


 Dim rdsDS as new RDS.DataSpace

 set bo = rdsDS.CreateObject("Lib.BusinessObj", "http://skonnard.com")
 result = bo.SomeMethod("Hello World")
      Like CIS, the object creation and method invocation happen over HTTP, making it possible for DCOM to get through the firewall. But like CIS, this solution is platform-specific, and the server also relies on an ISAPI DLL running on IIS. All business components that you want to expose through this mechanism must be configured differently in the registry than the way a standard DCOM component is registered. Furthermore, the client must have the appropriate RDS infrastructure in place for this communication link to work properly.
      Remote scripting is another technology that makes it possible to call server-side script functions directly from a browser's client-side script over HTTP. Microsoft implements remote scripting through a Java applet that runs in either Netscape Navigator or Microsoft Internet Explorer. Once you have the remote scripting runtime files configured properly on your Web server and within your client-side HTML files, you can start calling functions that live in your server-side ASP pages directly from DHTML. The following snippet illustrates some client-side JScript code that gets called in response to a button's onclick event:

 function button_onclick() {
    var obj = RSGetASPObject("http://skonnard.com/myfunctions.asp");
    var result = obj.SomeMethod("Hello World");
 }
      You can think of the ASP file as the class, and RSGetASPObject as a special type of moniker that binds you to the class (similar to CoCreateInstance). If you think about it, this is just another way to call methods over HTTP. Although this technology works from within different scripting languages on the client, it's tied to ASP and IIS on the server.
      And finally, even the most basic Visual Basic WebClasses or custom ASP pages are similar to SOAP. Both of these technologies make it possible to call server-side business objects over HTTP. For example, the following ASP page (which is similar to the functionality of a WebClass-generated ASP file) creates an instance of the Lib.BusinessObj component and invokes SomeMethod, passing the string sent by the client:

 <%
 set obj = Server.CreateObject("Lib.BusinessObj")
 obj.SomeMethod Request.QueryString("param1")
 %>
      Simply sending an HTTP request for the given ASP page makes it possible to invoke SomeMethod remotely. A client would invoke SomeMethod using the following URL:

 http://skonnard.com/soaplike/businessobj.asp?param1=hello+world
      At first, technologies like CIS, RDS, and Remote Scripting seem to resemble SOAP, but this last example is actually a closer fit. Since ASP pages are called via HTTP, any client application capable of sending HTTP requests can invoke SomeMethod on Lib.BusinessObj regardless of platform or language. Similarly, if you write a Perl CGI script that happens to call a Perl object, any HTTP client capable of requesting the CGI script can also indirectly invoke the Perl object.
      As you can see, SOAP is not an entirely new concept. I've described several similar technologies available on the Windows platform today. SOAP attempts to codify the main concept behind these existing practices into a simple and generic protocol that can serve as an industry standard.

SOAP Requests
      Imagine a component that lives somewhere on the Internet that implements the PurchaseBook method on the purchase_book interface. This method would be invoked for a user to purchase a book from an online bookstore. The following HTTP request represents how you would invoke such a method using the SOAP protocol:


 POST /cgi-bin/purchase-book.cgi HTTP/1.1
 MethodName: PurchaseBook
 InterfaceName: soap:cdl:com.develop.demos.purchase_book
 MessageType: Call
 Content-Type: text/xml-SOAP

 <PurchaseBook>
    <ISBN>0201379368</ISBN>
 </PurchaseBook>
      This HTTP request points to a uniform resource identifier (URI) of /cgi-bin/purchase-book.cgi. Since the SOAP specification says nothing about how a component is activated, it's up to the code behind this URI to decide how to activate the component and invoke the specified method.

SOAP HTTP Headers
      You may have noticed that the Content-Type header uses a value of text/xml-SOAP. SOAP defines this value to identify an HTTP entity-body containing an XML-encoded method invocation or response. All SOAP requests and responses must use this Content-Type value to be recognized.
      SOAP defines three extended HTTP headers. Two of these headers, MessageType and MethodName, must be used with every SOAP request. The third header, InterfaceName, is optional. The MessageType header defines whether the given HTTP body contains a method call or a method response and must contain the values Call or CallResponse, respectively. The MethodName header defines the name of the method to invoke. The optional InterfaceName header defines the name of the interface to which MethodName belongs.
      Because of HTTP's extensibility characteristics, you can create custom headers for application-specific purposes without any problem. But it is possible that other applications may decide that a MethodName header is exactly what they need for their application-specific purpose. Like anything that's truly extensible, using custom headers is prone to future conflicts. To address this issue, the HTTP Extension Framework has been proposed and submitted to the W3C as an Internet Draft (http://www.w3.org/Protocols/HTTP/ietf-http-ext/).
      The HTTP Extension Framework makes it possible to associate an extension identifier, which is simply a URI, with the custom HTTP headers used for application specific purposes. The extension identifier acts as the extension namespace and makes it possible to avoid future conflicts. The extension framework also provides a mechanism for making the extension declaration mandatory (using the M- syntax). By simply prefixing the HTTP method with M-, such as M-POST, the HTTP server is required to find and understand the identifier in the extension declaration.
      You'll notice that the SOAP request shown earlier uses a POST for the HTTP method. While the SOAP specification allows both POST and M-POST requests, it states that clients are required to first attempt the request using M-POST. If the client receives a response of "501 Not Implemented" or "510 Not Extended," it should try the request again using a standard POST. The specification also allows the client to continue using standard POST requests against that same server for the next 24 hours, at which point it's required to attempt another M-POST request to account for server or firewall upgrades.
      The following example illustrates how to convert the previous example into an M-POST request:


 M-POST /cgi-bin/purchase-book.cgi HTTP/1.1
 Man: "http://www.microsoft.com/protocols/ext/SOAP"; ns=01
 01-MethodName: PurchaseBook
 01-InterfaceName: soap:cdl:com.develop.demos.purchase_book
 01-MessageType: Call
 Content-Type: text/xml-SOAP

 <PurchaseBook>
    <ISBN>0201379368</ISBN>
 </PurchaseBook>
      Again, the M-POST method specifies that an extension declaration is mandatory for this HTTP request, and therefore a Man header must be present. The Man header contains the extension identifier along with a two-digit extension prefix. The prefix is used on each custom HTTP header that belongs to the extension, as shown in this example. This mechanism is similar to the XML namespace standard, which allows an arbitrary URI to scope a set of identifiers.
      You may be wondering why additional HTTP headers for MessageType, MethodName, and InterfaceName are used. Couldn't this information be embedded in the SOAP XML payload? The answer is yes—SOAP could have left off these headers and contained the information in the XML payload. However, the reason for using HTTP headers has to do with firewall filtering.

Firewall Filtering
      Firewalls can set filters for HTTP requests with a Content-Type: text/xml-SOAP. They can also force clients to use only M-POST by prohibiting regular POSTs of Content-Type: text/xml-SOAP. Since firewalls can force the use of M-POST, they can also be configured to allow only certain interfaces or methods to pass through by looking at the InterfaceName and MethodName extension headers defined by SOAP.
      As outlined in the SOAP specification, the MethodName header is always required. If an interface name is required to perform the operation, the InterfaceName header must also be present. The SOAP server is required to deny the request if it doesn't understand these headers or a header doesn't match the corresponding information contained in the XML payload.
      Without these SOAP headers, firewalls would have to scrape through the XML payload to filter by method name, interface name, or even message type. This would require firewalls to be more SOAP-aware.

SOAP XML Payload
      The SOAP XML payload contains the encoded method-call information. In SOAP, the XML payload serves the same purpose as the Network Data Representation in DCOM or the Common Data Representation in CORBA. For a SOAP request, the XML payload consists of several elements including a root element, a method element (referred to as the call element), and optional header elements:


 <SerializedStream>        <!-- root element -->
     <headers>             <!-- headers element -->
         <!-- header elements go here -->
     </headers>
     <PurchaseBook>        <!-- call (method) element -->
         <!-- parameter elements go here -->
     </PurchaseBook>
 </SerializedStream>
      The SOAP root element is the top element in the XML payload tree. It provides the serialization context for the SOAP method call data stream. Hence, the SOAP specification gives it the name SerializedStream. If SerializedStream is going to have only a single child element for a given method call (meaning it won't use any SOAP header elements), using the root SerializedStream element is optional. For example, this XML payload

 <SerializedStream>    <!-- root element -->
    <PurchaseBook/>    <!-- call (method) element -->
 </SerializedStream>
is equivalent to this one:

 <PurchaseBook/>        <!-- root & call (method) element -->
      The SerializedStream element must contain an attribute named main, whose value is a standard URI fragment identifier that points to the call element for the given request. If a headers element exists, it must also contain another URI fragment identifier named headers, which references the headers element:

 <SerializedStream headers="#ref-0" main="#ref-1">
    <headers id="ref-0">
       <!-- header elements go here -->
    </headers>
    <PurchaseBook id="ref-1">
       <!-- parameter elements go here -->
    </PurchaseBook>
 </SerializedStream>
These reference attributes make it possible for SOAP implementations to do quick retrievals of the call or headers elements by ID. The SerializedStream element may also contain a serializationPattern attribute, which identifies the version of the SOAP specification that this message was coded against.
      The call element contains all the information related directly to the method invocation. The element name must be the same as the method name used in the MethodName HTTP header. The element must contain an id attribute that distinguishes it from other child elements of the root SerializedStream element. The call element also contains a child element for each [in] and [in/out] parameter for the given method. These elements can use either the defined parameter name as the element name or a more generic approach that allows you to use _ _param0, _ _param1, ... _ _paramn, where n is the number of parameters minus one. For example, this payload

 <PurchaseBook>
    <ISBN>0201379368</ISBN>
 </PurchaseBook>
is equivalent to this one:

 <PurchaseBook>
    <_ _param0>0201379368</_ _param0>
 </PurchaseBook>
      The headers element may contain additional information not directly related to the method invocation for the given request. The headers element must contain an id attribute that distinguishes it from other child elements of the root SerializedStream element. The headers element also contains a list of header entries. The SOAP specification lists some standard header entries you can use including InterfaceName, MethodSignature, and UnorderedParams. You can also pass any other type of implicit information that needs to flow with the request, but is not directly related to the method invocation, such as a transaction ID or session state information (think cookies).

 <SerializedStream SerializationPattern="urn:schemas-microsoft-com:
 soap:v1"
 headers="#ref-0" main="#ref-1">
    <headers id="ref-0">
       <InterfaceName>
        soap:cdl:com.develop.demos.purchase_book
       </InterfaceName>
       <CustomerID>
        CDFE06E0-4DB4-4809-A7CF-4DDA32D5B081
       </CustomerID>
    </headers>
    <PurchaseBook id="ref-1">
       <_ _param0>0201379368</_ _param0>
    </PurchaseBook>
 </SerializedStream>

SOAP Response
      A SOAP response should be identified by a value of CallResponse in the MessageType HTTP header. A response contains a response element instead of the call element in the payload. The response element should be named the same as the method name, with Response tacked on the end. For example, for the method PurchaseBook, the response element would be named PurchaseBookResponse.
      If the method returns a value, the response element may contain a _ _return element containing the return value:


 <SerializedStream
    SerializationPattern="urn:schemas-microsoft-com:soap:v1"
    headers="#ref-0"
    main="#ref-1" >
    <headers id="ref-0" >
       <InterfaceName>
         soap:cdl:com.develop.demos.purchase_book
       </InterfaceName>
    </headers>
    <PurchaseBookResponse id="ref-1" >
       <_ _return>Thank you!</_ _return>
    </PurchaseBookResponse>
 </SerializedStream>
It will also contain one child element for each [in/out] or [out] parameter. Again, these element names can either be the same as the defined method names or you can use the _ _paramN approach.
      If the method returns an error, the response element will contain a child element named _ _fault. The fault element can contain detailed error information for the given request including a fault code, a fault string, and a special run code that tells you if the request reached the destination:

 <SerializedStream
    SerializationPattern="urn:schemas-microsoft-com:soap:v1"
    headers="#ref-0" main="#ref-1" >
    <headers id="ref-0" >

       <InterfaceName>
         soap:cdl:com.develop.demos.purchase_book
       </InterfaceName>
    </headers>
    <PurchaseBookResponse id="ref-1" >
       <_ _fault>
          <faultcode>400</faultcode>
          <faultstring>Bad Request</faultstring>
          <runcode>1</runcode>
       </_ _fault>
    </PurchaseBookResponse>
 </SerializedStream>

SOAP Security
      What about SOAP and security? Besides the firewall security benefits of designing SOAP using extended HTTP headers, the SOAP specification does not define any protocol-specific security features. Because SOAP is layered on top of HTTP, it may utilize any standard HTTP security feature or any endpoint application-specific security feature. SOAP requests are free to take advantage of HTTP authentication mechanisms as well as SSL for secure channel communications (using HTTPS).

A Generic SOAP Client
      I've provided a generic SOAP client for Internet Explorer 5.0 to accompany this article (see Figure 1). You can download this sample from the link at the top of this article or from my personal Web site at http://www.skonnard.com/soap. The sample will help you learn the SOAP protocol, and before you know it you'll be making your first SOAP method calls.

Figure 1: Generic SOAP Client
      Figure 1: Generic SOAP Client

      This SOAP client allows you to easily build a SOAP request to any SOAP endpoint. You type in the endpoint you want to call along with the method and interface names for the given method call. The sample builds a standard SOAP payload and includes the appropriate SOAP HTTP headers in the request (including Content-Type, MessageType, MethodName, and InterfaceName). It also gives you a starting point for the XML payload. As you type in the method and interface names, it will add the call tag using the method name and a header tag using the interface name. Then all you do is type in any parameter values inside of the call tag (where it says ENTER_ PARAMETERS).
      The client also allows you to specify whether you will use POST or M-POST for a given request. If you will use M-POST, it allows you to enter the extension identifier along with an associated prefix. The client will then include the extension declaration in the HTTP request and prefix the SOAP HTTP headers with the supplied extension prefix. Not all HTTP servers are configured to support the M-POST method, so the client allows you to use POST.
Figure 2: SOAP Request
      Figure 2: SOAP Request

      After you've built the SOAP request, press the Call Method button to send the request to the specified endpoint. After the call returns, the client will display all of the SOAP request and response information to help you become more familiar with the protocol specifics (see Figure 2 and 3).
Figure 3: SOAP Response
      Figure 3: SOAP Response

      The sample also includes a handful of predefined SOAP endpoints that exist on test SOAP servers at DevelopMentor (http://www.develop.com/soap). Some of the endpoints are COM components implemented in Visual Basic, while others are Perl objects running on a Linux box. To use one of these endpoints, select it from the Test Endpoints combobox and the entire SOAP request will automatically appear in the form. For more detailed descriptions of the different test SOAP endpoints, click on [show descriptions] (see Figure 4). When you choose one of the Perl endpoints (reverse_string), you're calling a Perl object directly from a Windows script.
Figure 4: Test Endpoints
      Figure 4: Test Endpoints

      Although I've covered the basics of SOAP in this section, you'll want to read the SOAP specification for more details. As you can see, SOAP itself is very simple. It only defines how to encode and transmit method invocations and responses using HTTP and XML. To do something useful with SOAP, you'll have to write code to build and send the SOAP request from the client as well as code to understand the SOAP response on the server. While you could surely do this by hand, it would make things much easier if there were some natural language bindings for SOAP.

Language Bindings
      To make SOAP work, there has to be code running on the client that is responsible for building the SOAP request. There must also be code on the server that is responsible for understanding the SOAP request, invoking the specified method, building the response message, and returning it to the client. The SOAP specification leaves these implementation details up to the developer.
      In the case of my generic SOAP client for Internet Explorer 5.0, I've provided the test endpoints that automatically generate the appropriate SOAP request and payload. If you want to call something other than one of the test endpoints, you have to type in some of the SOAP HTTP/XML information by hand. In order for clients to start using SOAP quickly, you need transparent language bindings that hide the SOAP details. After all, when you call a DCOM method, you don't have to worry about building the DCOM packets; it all happens transparently, behind the scenes. For SOAP to really take off, you need that same level of transparency for SOAP clients and servers.
      Because the SOAP protocol has been kept simple, implementing these language bindings shouldn't be a major development effort. Over the past few months, DevelopMentor has been working on SOAP implementations for Perl, the Java language, and COM. You can get information about these reference implementations from DevelopMentor's SOAP site at http://www.develop.com/soap.
      To illustrate SOAP's simplicity, it took one developer about one month to write a robust and complete Perl implementation of SOAP. This implementation allows you to write standard Perl objects and expose them through SOAP. For example, consider the following Perl object that contains the reverse_string method (this is one of the test endpoints available in the sample):


 package Demo;
 use strict;
 sub new { bless \do{my $self}; }
 sub reverse_string {
     my ($self, $s) = @_;
     return scalar(reverse $s);
 }
 1;
      To expose this Perl object through SOAP, you could create the following simple CGI script that uses the DevelopMentor Perl SOAP implementation:

 #! /usr/bin/perl
 use strict;
 use SOAP::Dispatcher;

 my $d = SOAP::Dispatcher->new();
 my $classes = ['SoapOnLinux', 'Demo'];
 $d->handle_cgi_post($classes);
      This CGI script simply uses SOAP:: Dispatcher to process the SOAP request. The $classes variable passed to handle_cgi_post lets you to specify the class names that are allowed to be called from the outside world— this adds an additional layer of application security.
      Remember, using SOAP you can call this Perl object from any client on any platform using any language that supports HTTP and XML. The Perl language binding makes it especially easy to make SOAP method calls from Perl clients. For example, the following Perl script calls the reverse_string method using SOAP:

 use strict;
 use SOAP::Proxy;

 my $proxy = SOAP::Proxy->new();
 $proxy->set_itf_name('com.develop.demos.string_test');
 $proxy->set_endpoint('http://localhost/testendpoint/nph-testcgi.pl?
 class=Demo');
 print $proxy->reverse_string('!dlrow olleH');
      Notice how simple this script looks. There are no signs of HTTP, and no signs of XML. It creates a new SOAP::Proxy, sets the endpoint and interface name, and starts calling methods through the proxy. Everything else happens transparently. The proxy will take care of setting the appropriate HTTP headers in the request and encoding the reverse_string method call using XML. It will also receive the HTTP response and process the XML payload for the result.
      DevelopMentor has also developed a SOAP binding for standard COM clients and servers. Any COM server can be exposed through either an ASP page or an ISAPI DLL. The following ASP allows you to call methods on the VBSoapSrv.VBSoapTest component implemented in Visual Basic:

 <%@ language=javascript %>

 <object classid="clsid:2AD287C9-D8C2-4F53-A7B3-D297FDBF097A"
    id=SoapCall runat=server></object>
 <object progid="VBSoapSrv.VBSoapTest" id=TargetObject
 runat=server></object>
 <script language=javascript runat=server>

 if (SoapCall.Init("soap", false))
 {
     SoapCall.Invoke(TargetObject);
     SoapCall.WriteResponse();
 }

 </script>
      This creates an instance of the VBSoapSrv.VBSoapTest component through an <OBJECT runat=server> tag and delegates the work to the SoapCall component (which acts like a COM stub) to take care of the rest. The SoapCall component performs the same role as the SOAP::Dispatcher in the Perl implementation.
      On the client side, DevelopMentor provides a transparent proxy that hides all the SOAP details. And to make things even easier, they offer a SOAP moniker to bind your code to the proxy. Check out the following example, which uses the SOAP moniker:

 Dim itf As VBSoapSrv.VBSoapTest

 Private Sub Command1_Click()
    set itf = GetObject("dm.soap:http://soap.develop.com/soap/page.asp")
    strOrigin = itf.GetOrigin()
    MsgBox strOrigin
 End Sub
      SOAP can't get much more transparent than that. The proxy builds, sends, and receives the underlying SOAP request for each method call (like GetOrigin).
      Besides the Perl and COM implementations, there is also a Java language binding. As of the writing of this article, both the COM and Java bits were still under development. Point your browser to http://www.develop.com/soap for more details on the current state of these implementations.
      At this point, I want to emphasize that these language bindings are not part of SOAP itself. They only make SOAP easier to use from their respective environments. Other organizations are free to produce their own SOAP implementations that improve upon these and make SOAP a more integral part of their products and services.

Additional SOAP Resources
      Userland Software, Microsoft, and DevelopMentor drafted the original SOAP specification back in 1998. The current SOAP specification has been submitted to the Internet Engineering Task Force and can be read online at http://msdn.microsoft.com/ workshop/xml/general/SOAP_V09.asp. Public statements about plans to support the SOAP protocol have been made by several companies:

      For more information on the development of the SOAP protocol and the different ongoing SOAP implementations, be sure to visit DevelopMentor's SOAP site, where you can read the SOAP FAQ and join the SOAP mailing list.

Conclusion
      Although SOAP can be made easier to use through natural language bindings, SOAP does not mandate an API of any kind; a language binding is strictly an implementation that makes SOAP more accessible and easy to use. SOAP also doesn't attempt to address the more complicated distributed object protocol services such as object activation, marshaling objects/references, garbage collection, or bidirectional communications. SOAP doesn't prevent you from using any of these services; they are simply implementation details that can be layered on top of the SOAP protocol.
      SOAP is simple. It is nothing more and nothing less than a protocol that defines how to access services, objects, and servers in a platform-independent manner using HTTP and XML. As the industry embraces this technology, it will open up a new world of interoperability that promotes further progress toward developers working together.

From the January 2000 issue of Microsoft Internet Developer.