Home

Who are we

Articles

SOAP - A Quick Intro to Webservices

XML-RPC - A Five-Minute Tutorial

Installing Apache2 and mod_perl (Windows XP)

Links

Untitled Document

A SOAP RPC Server and Client in Perl

We will start off writing first a service and then a client to access our service in Perl. The package we are going to be using is SOAP::Lite by Paul Kulchenko, the same author who also wrote XMLRPC::Lite that we used for our quick tour on XML-RPC. Our aim is it to re use most of the code we wrote in the previous XML-RPC examples. For the server that means that we try to keep the Date class and the dateInfo method with little changes and only build a different server structure around that.

The SOAP Server in Perl

 
dateInfoServer.pl
 
#!/usr/bin/perl
 
package Date;
use strict;
use Time::localtime;
use SOAP::Transport::HTTP;
 
sub dateInfo {
   my $self = shift;
   my $option = shift;
   
   my $time = localtime;
   my $year = $time->year()+1900;
   my $month = $time->mon()+1;
   my $day = $time->mday();
   my $hour = $time->hour();
   my $min = $time->min();
   my $sec = $time->sec();
   
   if ($option eq "date") {
      return [sprintf("%02d/%02d/%04d", $month, $day, $year)];
   } elsif ($option eq "time") {
      return [sprintf("%02d:%02d:%02d", $hour, $min, $sec)];
   } elsif ($option eq "all") {
      return [sprintf("%02d/%02d/%04d", $month, $day, $year),
      sprintf("%02d:%02d:%02d", $hour, $min, $sec)]
   } else {
      die SOAP::Fault->faultcode("Server.ExecError")
         ->faultstring("Unknown option: $option");
   }
}
 
my $port = 9000;
my $host = 'localhost';
 
SOAP::Transport::HTTP::Daemon
   ->new(LocalAddr => $host, LocalPort => $port)
   ->dispatch_with({ 'urn:/Date' =>'Date' })
   ->on_action(sub{})
   ->objects_by_reference('Date')
   ->handle;
exit;

As we can see the code is only minimally different from the example in XML-RPC. The method dateInfo is unchanged except for the part that returns a SOAP fault if an undefined option is passed on to dateInfo. The difference to XMLRPC::Lite can be found in the implementation of the server. Here SOAP::Transport::HTTP::Daemon is used to setup the server. Let's take a look at the details:

  • dispatch_with() defines the name space of the method, it basically states where under http://localhost:9000/ to find the service. Instead of dispatch_with we could also use the probably better known method dispatch_to('urn:/Date', 'Date').
  • objects_by_reference instructs the server which package or class to use to locate the method call.
  • on_action is a bit tricky. It allows to set a handler for a given SOAP action (as defined by SOAPAction in SOAP 1.1 or the action attribute in SOAP 1.2). By default only actions of form uri#method will be processed by SOAP::Lite servers all others will be filtered out. This is fine for communicating with a SOAP::Lite client, because the client sets that by default, but gives problems when using other implementations. To simplify the access, we override the default handler with the empty handler sub{} requiring no specific SOAP action settings.

The SOAP dateInfoClient in Perl

Now that we've got the server, we need a client:

 
dateInfoClient.pl
 
#!/usr/bin/perl -w
 
use strict;
use URI;
use SOAP::Lite;
 
my $option = $ARGV[0];
 
# set up the proxy
my $service = "http://localhost:9000";
my $dateProxy = SOAP::Lite->uri('urn:/Date')
   ->proxy($service);
 
my $result = $dateProxy->dateInfo(
   SOAP::Data->name(option => $option));
if ($result->fault()) {
   die "Error: ". $result->faultstring();
}
my $response = $result->result();
 
# read out the response
unless (defined $response) {
   die "Call returned error";
}
 
if ($option eq "date") {
   print "Current server date is ". $response->[0] ."\n";
} elsif ($option eq "time") {
   print "Current server time is ". $response->[0] ."\n";
} elsif ($option eq "all") {
   print "Current server date is ". $response->[0] ."\n";
   print "Current server time is ". $response->[1] ."\n";
}
 
exit;

That is it. We start off setting up the proxy by providing it the server address http://localhost:9000/ and the name space or the service uri('urn:/Date'). That is the same value as we defined with dispatch_with in dateInfoServer.pl. One of the two things to keep in mind since all SOAP implementation have a similar feature. Once we have the proxy we can simply treat is as the Date class itself and call the method dateInfo() on it. And here is the second thing to keep in mind: When passing on the option to the proxy we explicitly 'declare' of the data type of option. This is not required but in general very good practice (and admittedly something that should be done on the server side in Date::dateInfo as well) since it helps the different SOAP implementations to correctly translate the information stored in xml format into native types. As you remember, unlike XML-RPC there is no standard definition of data types in SOAP, so the xml parser might correctly extract the data from the message body, but e.g. may have more than one option to translate the data into a native type. Perl and python are not too picky about this, but other languages like java are.

The proxy method call returns an object of type SOAP::SOM, which provides access to the deserialized content of the SOAP response. In the example here we only look at the decoded values itself, which is returned by result(), but it's definitely worth looking at other features of SOAP::SOM as well. In cases where the default deserializer can not correctly resolve the xml data, e.g. in some cases where the xml data contains arrays, direct interaction with the

If you now startup the server and run the client you should get something like

 
dateInfoClient.pl all
Current server date is 09/16/2005
Current server time is 17:44:21

Great so far. Beginning here we could dig deeper into the topic of web services and cover topics like user authentication, security or the advanced messaging options that SOAP provides. Or we could go on to the more practical application of attaching the service to an apache web server instead of running a standalone service. However I only want to briefly touch one topic, WSDL, the web service description language.

If we implement both server and client and have no intentions to allow access to outsiders then we pretty much don't care that others know how to make use of our services. In fact we probably would want to hide that as much as possible for security reasons. However in the best use of web services, the opposite should be the case. Anyone who is interested should be able to access the service, that includes people who don't know who you and I are and typically don't even care about us. For them to be able to access our service we need to describe how to access the service we provide. And, to make a short story long, that is what WSDL is all about.

Previous: Basic SOAP Specifications