An
introduction to SOAP Dynamically generated HTML content works
fine in Web browsers, but it presents a nightmare for anyone trying to utilize
that data with other programs. For example, you can easily view an auction site
in a browser, but an application would require a complex HTML parser to read
your bid's status from the same site. Worse, you would need a different parser
to track a different auction site, and the simplest redesign of either site
could throw off your program. Web services solve this problem with a
consistent and easy method for accessing online information. As more online
services are offered, new applications can be built to interact directly with
them. For example, that Web-based auction site could let you write software that
automatically updates your bids based on the status of a bid on a different
auction site. Or you could edit your Web log with your favorite word processor
once the site and application were both speaking the same language. Web services
could potentially create a whole new type of Web. A protocol created by Microsoft,
DevelopMentor, and Userland Software and backed by companies that include IBM,
Lotus, and Compaq gives a big push toward that vision. Simple
Object Access Protocol (SOAP) exchanges application data over HTTP in XML
encoding. Because HTTP is ubiquitous and XML parsers are widely available, SOAP
can be easily adopted and quickly developed. The trade-off is speed; SOAP won't
replace lower-level technologies, but it works where interoperability is
paramount. SOAP toolkits are already available for most popular development
environments, including Python, Java, Visual Basic, and, of course, Perl.
Programmers experienced with remote procedure call APIs such as Java's RMI or
Microsoft's COM+ will find the SOAP toolkits familiar. In this article, we'll look at how to use
Perl to both provide Web services and to build applications on top of SOAP
servers. Because Perl is available on many platforms, Perl-based SOAP services
are an easy way to tie diverse computing environments together by using a common
high-level format. Soon you'll be exploiting this powerful new technology in
ways that you never imagined.
http://cnet.com/webbuilding/0-7704-8-4874769-1.html
By James
Scheinblum
(2/26/01)
Get started with SOAP
First you'll want to download the SOAP::Lite
toolkit, a Perl module by Paul Kulchenko. Once you've installed it and any requisite
libraries, you're ready to create a SOAP service.
Before we create a SOAP listener, we need
to understand how SOAP handles requests. On the server side, SOAP matches the
incoming request to a Perl object by reading the class name and function name
out of a SOAP envelope, the XML file sent from the client. For the
following examples, we'll use a class World
that has two functions,
HelloWorld
and GoodByeWorld
.
package World;
sub new {
bless {}, shift;
};
sub HelloWorld {
my ($self) = @_;
return "Hello World\n";
};
sub GoodByeWorld {
my ($self,$adjective) = @_;
return "Goodbye $adjective World\n";
}
1;
Though you may never have to actually see a
SOAP request, it can help to know what's going on behind the curtain, especially
when it comes time to debug your requests. Here is a very simple SOAP request to
the World
class calling the HelloWorld
function.
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/1999/XMLSchema">
<SOAP-ENV:Body>
<namesp1:HelloWorld xmlns:namesp1="World"/>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
You can see where the envelope and its body
begin in the XML; the HelloWorld
function is called inside the
body. The namespace is the name of the function to be called on the server, and
the XML namespace is the name of the class from which the function will be
called. In this case, we're calling the function HelloWorld
in the
class World
. When GoodByeWorld
is called, everything
pretty much looks the same, except that the SOAP body passes a parameter:
<SOAP-ENV:Body>
<namesp2:GoodByeWorld xmlns:namesp2="World">
<c-gensym9 xsi:type="xsd:string">cruel</c-gensym9>
</namesp2:GoodByeWorld>
</SOAP-ENV:Body>
If this is confusing, don't worry: The toolkit will hide the actual SOAP transaction from you.
Serve up SOAP
Because SOAP runs over HTTP, we can take advantage of Perl's existing
relationship with Web servers. First, we create a simple CGI script to pass the
request to our class and return the SOAP response to the client. Make sure that
your server supports CGI scripts and that you make the script executable. Here's
a CGI script that receives a SOAP request for the World
class from
the previous page:
#!/usr/bin/perl
use SOAP::Transport::HTTP;
use World;
SOAP::Transport::HTTP::CGI
-> dispatch_to('World')
-> handle;
That's all; the SOAP module takes care of
the rest. Create a CGI script like the one above for each SOAP class that you
wish to call. You only need to make sure that the first dispatch_to
argument is the name of the class you wish to bind. The class must behave like
any other, with a new
method $self
as the first
argument to all method calls. Create the module with the package name at the top
and save it with the .pm suffix.
SOAP::Lite can also dynamically load
modules based on a requested name, a capability that lets you create one CGI
script that loads any module from a specified directory. It's less secure and
gives you less control over which modules are loaded, but a directory of SOAP
modules can be more convenient to manage. To dynamically load modules, remove
the use
statement and make the SOAP module directory the first dispatch_to
argument:
#!/usr/bin/perl
use SOAP::Transport::HTTP;
SOAP::Transport::HTTP::CGI
-> dispatch_to('/home/httpd/soap_modules/')
-> handle;
Create a SOAP client
A SOAP client is just as easy to create as a SOAP server. You just have to load
the SOAP::Lite module and know some information about the remote service (or
endpoint). In fact, gathering that information is the most difficult part.
You'll need to know the endpoint URL, the method namespace URI, and the remote
method's names and parameters. Once you have this information you can create a
SOAP client. Let's make one for the server we just created.
use SOAP::Lite;
my $s = SOAP::Lite
->uri('World')
->proxy('http://soapserver.mycompany.com/soap/soapserver.cgi')
->HelloWorld();
print $s->result();
my $s = SOAP::Lite
->uri('World')
->proxy('http://soapserver.mycompany.com/soap/soapserver.cgi')
->GoodByeWorld("cruel");
print $s->result();
In this example, uri
accepts
the name of the class we're accessing on the remote server. Not every SOAP
implementation uses this convention, however, so you'll have to find out what
the URI should be. The proxy
method accepts the URL of the endpoint
SOAP handler. You must provide URI
and proxy
for every
connection in order for your SOAP request to be completed. The last function is
the method that you wish to call; here we call HelloWorld()
and GoodByeWorld("cruel")
and retrieve the result via the result
function. Note that even
though both methods are from World
, we've instantiated the class
twice over two separate transactions. This means that the state of one instance
is unknown by the other, so you can't (for example) set a class value with one
method and retrieve it with another.
A SOAP service may require a specific
SOAPAction field, a parameter sent in the HTTP header. You can set it with an on_action
method that overrides the default handler. Here's an example:
my $s = SOAP::Lite
->uri('World')
->on_action(sub { return "/Action#Action" })
->proxy('http://soapserver.mycompany.com/soap/soapserver.cgi')
->GoodByeWorld("cruel");
print $s->result();
Advanced SOAP options
If you're curious or need debugging information, SOAP::Lite gives you the option
of viewing the client-server transactions in great detail. This verbose output
includes how the request is processed and is very handy for tracking down
errors. Most errors result from a mismatched URI
or proxy
address and will show up in the text of the SOAP packet. Add +trace =>
all
after use SOAP::Lite
to send all debugging output to the
STDERR output stream.
use SOAP::Lite +trace => all;
my $s = SOAP::Lite
->uri('World')
->proxy('http://soapserver.mycompany.com/soap/soapserver.cgi')
->GoodByeWorld("cruel");
print $s->result();SOAP::Lite also supports a feature called Autodispatch that lets you bind remote methods into the execution of your program. When Autodispatch is enabled, methods that aren't locally available are automatically sent to a remote server for execution there. Autodispatch makes using SOAP a transparent process; once you establish the remote server, you can write your script without further SOAP references. Enable Autodispatch with the
+autodispatch
flag:
use SOAP::Lite +autodispatch =>
uri=>"World",
proxy=>'http://soapserver.mycompany.com/soap/soapserver.cgi';
print HelloWorld();
print GoodByeWorld("sweet");
Because they aren't locally defined, the HelloWorld
and GoodByeWorld
functions are automatically sent to the remote
server named in proxy
for execution. Using Autodispatch is like
inheriting from another class, so be sure to define a function with the same
name as the one you're trying to call on the remote server.
As you can see, using SOAP with Perl is easy. It's simple to set up services and make requests. Now you can offer new Web services or take advantage of other SOAP servers to bring more value to your site.