Let's look at a simple SOAP conversation. Our examples will demonstrate SOAP on top of HTTP, which is the most common configuration. There may be slight differences when working with other protocols.
HTTP is stateless, meaning that every connection between two computers consists of one request (from the client to the server) and one response (from the server back to the client). The request and response are each divided into two parts, known as the headers and the body. Of course, the client and server can add any other headers they want, opening the door to all sorts of specialized communications protocols.
The body of a SOAP request or response will be in XML. (If you have never worked with XML before, don't worry; while it can be a deep and intriguing topic, you don't need to know much XML to work with SOAP.) Each SOAP message—a request or response—consists of an optional SOAP header and a mandatory SOAP body wrapped inside of a SOAP envelope. The envelope identifies the contents as belonging to SOAP and sets out the namespaces that will be used for the rest of the message. The headers describe the data in the body, and the body contains the method call or its results.
In order to invoke an object on a remote server via SOAP, we will have to open an HTTP connection to the appropriate URL, identifying the object via the SOAPAction header. We send an XML document containing a SOAP envelope, inside of which our SOAP headers and body identify the method to be invoked on this object, as well as any parameters that the method might require. The client must additionally be prepared to parse the response returned by the SOAP server, extracting data structures contained in that response and using them as necessary.
A SOAP server performs complementary actions, receiving the SOAP request, parsing its contents and invoking the appropriate method on the local computer with the passed parameters. The server also returns the SOAP response to the client, containing one or more values as necessary.
Now that you understand the terminology associated with SOAP, you can forget nearly all of it. SOAP implementations provide us with an abstraction layer that allows us to ignore the fact that it communicates via HTTP and that the request and response use XML. When your program invokes a remote object method using SOAP, it cares about receiving a response; the way in which the request and response are packaged is of little concern.
I'm going to write some demonstration programs in Perl using the excellent SOAP::Lite module written by Paul Kulchenko. This should give you some idea regarding how to write SOAP clients and servers, as well as how to integrate them into your web applications. Despite its name, SOAP::Lite offers a rich array of functionality and can be a great way to add SOAP functionality to your Perl programs. Similar SOAP libraries and objects are available for most major programming languages, so don't think that SOAP is available only for Perl.
Because SOAP acts as a proxy for an object, we first have to create an object whose methods will be available over the network. Listing 1 contains the simple “Text::Caps” Perl module, which handles two fairly useless methods:
capitalize, which takes a single string as a parameter and returns the capitalized version of that string
capitalize_array, which does the same thing as capitalize, but to each element in a list of strings rather than to a single string
Notice that while SOAP describes everything in terms of objects and methods, this sample module uses standard Perl modules and subroutines rather than object-oriented syntax. So, when I mention the capitalize method for the Text::Caps object, I really mean that we'll be invoking the Text::Caps::Capitalize subroutine.
SOAP is normally carried over HTTP, which sits on top of TCP/IP. This means that we can create a simple SOAP server by taking advantage of the TCP/IP socket code that comes with Perl. However, SOAP::Lite does much of the dirty work for us; we don't have to create the socket or wait on it. Rather, we create an object of type SOAP::Transport::HTTP::Dæmon, which knows how to act as the appropriate kind of SOAP server. You can see the source code for such a simple server in Listing 2.
The code is relatively simple yet will look odd to even the most experienced Perl programmers. That's because objects associated with SOAP::Lite usually return themselves to indicate success. This allows us to invoke more than one method in a single call. In other words, we can say
rather than the traditional
$object->method1(); $object->method2();You may choose to work with SOAP::Lite using either syntax, but the first version is common in documentation.
When we invoke the “new” constructor for SOAP::Transport::HTTP::Dæmon, we pass it two arguments: the name of the computer and the port on which the server should listen for connections.
Once we have created the server object, we must tell it where objects are located. This is a security feature, albeit one that can take some time to understand. Normally, Perl looks for modules in @INC, an array of directory names. When we import a module, Perl searches sequentially through each element of @INC until it finds our module. If it fails to find our module, Perl returns an error message.
However, since SOAP exposes our modules to the entire world, we must be careful before making them available. Perhaps some of our modules return confidential data or manipulate information in a relational database. In order to ensure that only those modules we wish to expose are actually available via SOAP, SOAP::Lite completely ignores @INC when handling incoming SOAP requests. Only those modules explicitly mentioned in a call to dispatch_to(), or in a directory named in dispatch_to(), will be available via SOAP.
In a sense, dispatch_to() effectively defines the equivalent of @INC for incoming SOAP requests. If a module resides in a directory not mentioned in dispatch_to(), it will be invisible to SOAP requests. That this is not the same as modifying @INC.
Note that while I use /tmp for the examples in this article, it is a poor idea to use /tmp in this way in a real development or production system. If you want to put SOAP-related Perl modules in a separate directory from /usr/lib/perl, I strongly suggest that you keep it on the main file system, such as in /usr/lib/soaplite.
Practical books for the most technical people on the planet. Newly available books include:
- Agile Product Development by Ted Schmidt
- Improve Business Processes with an Enterprise Job Scheduler by Mike Diehl
- Finding Your Way: Mapping Your Network to Improve Manageability by Bill Childers
- DIY Commerce Site by Reven Lerner
Plus many more.