Enterprise Software

Write a Web service using SOAP::Lite

Implementing Web services with Perl is simple when using SOAP::Lite. Find out why you need little knowledge of SOAP to create a Web service, and then use our basic example as a starting point for your application.


SOAP::Lite is a Perl module that enables and facilitates the composition, transportation, and processing of SOAP messages. In this article, I'll walk you through using SOAP::Lite to build a very basic Web service. You'll be amazed at how little code or knowledge of SOAP is required to actually create a Web service with this toolkit.

Your first Web service
For our basic Web service, let's implement an echo service, which simply responds with the exact input it receives. Obviously, an echo service isn't very practical or useful in any real-world context, but writing it will allow you to focus more on the idiosyncrasies of SOAP::Lite and not get distracted by implementing something more complex. In addition to implementing this service, you should also implement a simple client to interact with it. I'll show you how to create one so you can then test the service.

The echo service accepts a single parameter named whatToEcho and returns the value of that element in a response element named whatWasEchoed. Let’s take a look at a sample SOAP request and response.

Example request:
 
<?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:SOAP-ENV=http://schemas.xmlsoap.org/soap/envelope/
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/1999/XMLSchema">
<SOAP-ENV:Body>
<namesp1:echo xmlns:namesp1="urn:Echo">
<whatToEcho>I am going to be echoed</whatToEcho>
</namesp1:echo>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>


Example response:
 
<?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:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/1999/XMLSchema">
<SOAP-ENV:Body>
<namesp24:echoResponse xmlns:namesp24="urn:Echo">
<whatWasEchoed>I am going to be echoed</whatWasEchoed>
</echoResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>


The anatomy of a SOAP::Lite Web service
SOAP::Lite provides many modules that can support a variety of transport protocols, such as POP3, SMTP, HTTP, and TCP. For this article, I'll focus on the most likely case for use: a simple CGI-based Web service communicating over HTTP. The following examples assume that you have access to a Web server, such as Apache or IIS, and know how to configure it to use Perl-based CGI scripts. You will need the following:
  • SOAP::Lite version 0.55
  • Access to a Web server capable of running Perl-based CGI scripts
  • A text editor

Echo service request handler
The first step in building the Web service is constructing the request handler, which contains the core application logic exposed as a Web service. SOAP::Lite makes exposing services easy by automatically dispatching requests to subroutines contained within Perl modules. SOAP::Lite uses the namespace of the request to determine which Perl module to dispatch the request to, and invokes the subroutine with the same name in that Perl module as the request method.

For that reason, your request handler is contained in a simple Perl module. The Perl module contains a subroutine for each exposed Web service method. For example, in the case of your echo service that consists of only one method, called Echo, you'd create a Perl module entitled Echo.pm, which consists of one subroutine called echo, like this:
1 #!/usr/bin/perl
2 # Filename: Echo.pm
3 # Echo Web Service Perl Module - This module is where requests to the
4 # Echo Web service will be dispatched.
5 # Author: Byrne Reese
6 package Echo;
7 use strict;
8 sub echo {
9 my ($self,@args) = @_;
10 return join(",",@args);
11 }
12 1;


On line 6, you specify the package name for the module and the name of your Web service. The name you choose is not completely arbitrary. In fact, the service/package name becomes the namespace that the service responds to. In this example, the name is simple: Echo. On lines 8 through 11, you implement the only method that is exposed in this Web service as a Perl subroutine. The method's name is Echo and it accepts one argument. If a user supplies more than one argument to the Echo method, it uses the Perl join function (line 10) to return all of the parameters concatenated together as the method's response.

You may notice that SOAP::Lite isn't referenced in any way in the above example. In fact, the above example could easily be any Perl module installed on a Web server, thus enabling you to expose virtually any kind of service. But be careful—arbitrarily exposing a service in this manner can be dangerous because it could make your entire Web server vulnerable to attack.

Echo service request dispatcher
The request dispatcher is the portion of the service directly exposed to the caller of the Web service. It resides on your Web server and is invoked as another CGI script. The following example demonstrates the implementation of a very basic request dispatcher:
1 #!/usr/bin/perl -w
2 # Filename: echo.cgi
3 # Echo Web Service - This Web service will echo any input and return
4 # it in its response.
5 # Author: Byrne Reese
6 use Echo;
7 use SOAP::Transport::HTTP;
8 SOAP::Transport::HTTP::CGI
9 ->dispatch_to('Echo')
10 ->handle;


As you can see, the SOAP::Transport::HTTP::CGI package makes dispatching SOAP requests to a Perl module trivial.

On line 6, you import the request handler for your service. This is the Perl module, which contains the subroutines to receive incoming SOAP. On line 7, you import the SOAP::Lite package, which contains all the logic to handle incoming SOAP requests. On line 9, the Perl module that will handle the incoming requests is specified. In this example, the value passed to dispatch_to should correspond with the module name on line 6. Then on line 10, the call is made to SOAP::Lite to process the request.

SOAP::Lite is capable of directing incoming requests to multiple modules. That capability allows you to create a single point of entry for all incoming SOAP requests. To do so, simply specify each module by its fully qualified name as an argument to dispatch_to. For even more flexibility, you can specify the full path to a directory that contains a set of Perl modules to which SOAP::Lite will dispatch requests. The following example is capable of dispatching requests to the My::Module::Name and My::Other::Module Perl modules, as well as any Perl module installed in the /Your/Path/To/Deployed/Modules directory:
SOAP::Transport::HTTP::CGI
->dispatch_to('/Your/Path/To/Deployed/Modules', 'My::Module::Name', 'My::Other::Module')
->handle;


To summarize how this works, let's take a look at some XML. When a call is made to SOAP::Transport::HTTP::CGI->handle(), SOAP::Lite invokes the subroutine with the same name as the root element name of the SOAP Body. It looks for that subroutine in the Perl module identified by the namespace of the root element of the SOAP Body. For example, the following SOAP request will result in SOAP::Lite dispatching the request to the subroutine called myMethod located in the MyWebService.pm Perl module:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Body>
  <namesp1:myMethod xmlns:namesp1="urn:MyWebService">
    <foo>bar</foo>
  </namesp1:echo>
</SOAP-ENV:Body>


Echo service client
The following Perl program is provided to facilitate sending messages to your new echo service. Only a few variables need to be substituted in the sample below to make this client work in your environment. On line 9, substitute the value of the $HOST variable with the URL pointing to your SOAP::Lite request dispatcher.
1 #!/usr/bin/perl –w
2 # Filename: echo_client.pl
3 # Client to send a message to the echo Web service
4 # Author: Byrne Reese byrne@majordojo.com
5 # Usage:
6 #    echo_client.pl <what to echo>
7 ###################################################
8 use SOAP::Lite; # +trace => 'debug';
9 $HOST   = "http://localhost/cgi-bin/echo.cgi";
10 $NS     = "urn:Echo";
11 $PHRASE =  shift; # read from the command line
12 my $soap = SOAP::Lite
13   ->readable(1)
14   ->uri($NS)
15   ->proxy($HOST);
16 my $som = $soap->echo(
17      SOAP::Data->name("whatToEcho" => "$PHRASE"));
18 print "The response from the server was:\n".$som->result."\n";
19 1;


For more information on writing SOAP clients, see our previous tutorial  on SOAP::Lite.

Putting the pieces together
With the above three code snippets, you have all you need to deploy your first Web service. Install the request dispatcher (echo.cgi) and the request handler (Echo.pm) to a cgi-bin directory on your Web server. Then use the sample client provided (echo_client.pl) to invoke the Web service. Be sure you modify the echo_client.pl program to make a call to the echo service you deployed, like this:
[localhost]$ perl echo_client.pl "Echo this statement"
The response from the server was:
Echo this statement


You can instruct SOAP::Lite to output all debugging information, including all of the HTTP headers and the SOAP request and response messages, by changing line 8 in echo_client.pl to the following:
8 use SOAP::Lite +trace => 'debug';

Just an example of what you can do
As you can see, SOAP::Lite handles most of the hard work for you and makes implementing a Web service much easier. However, the example covered in this article is much too simplistic to be of use in a commercial production environment. I merely used it to pique your curiosity about writing Web services and using SOAP::Lite. Once you understand how to use it, though, you can easily implement much more complex services.

Editor's Picks

Free Newsletters, In your Inbox