How to develop a CGI based BioMoby service using Perl MoSeS

This document summarises steps in order to develop (to implement) a CGI based BioMoby service using Perl MoSeS.

The main thing to understand is that MoSeS does not give you a full implementation of your service. You still need to program the business logic (e.g. to extract data from your database) - but you do not need to worry about the BioMoby and CGI details.

Table of Contents

Step 1: What is needed
Step 2: Service registration
Step 3: Service generation
Step 4: Service implementation
Step 5: Service testing
Step 6: Service deployment
Step 7: Service testing using CGI

What is needed

To implement SOAP services using MoSeS, you need to have the following installed on your machine:

  1. Perl - perl has to be installed on your machine
  2. A web server - this document assumes that you are using Apache
  3. Perl MoSeS - available on cpan
  4. MOBY-Client / MOBY-Server - either one will do; also available on cpan

Once you have installed Perl MoSeS and all of its dependencies on your machine, you will have to run through the MoSeS set up. This is only done once per user of MoSeS. For more information, please view the MOSES::MOBY documentation.

Service registration

In order to implement a Biomoby service, we must first register one in the registry of our choosing.

We can register a service using a perl script or one of the many GUIs created by the Biomoby developers. This tutorial will be using a simple perl script, but you are invited to try GUIs such as Dashboard or The Moby Registration Pages.

The service that we will be registering is going to be a simple echo service. To spice things up a little bit, our service will echo the reverse string that it receives.

The script that we will use for registering our service is shown below:

#!/usr/bin/perl -w
use strict;
use MOBY::Client::Central;

# instantiate a client to mobycentral
my $m = MOBY::Client::Central->new(
    Registries => { mobycentral => {
                       URL => "http://moby.ucalgary.ca/moby/MOBY-Central.pl",
                       URI => "http://moby.ucalgary.ca/MOBY/Central",
                     },
                  }
);

# give our new service a name
my $serviceName = "getReverseEchoString";

# give our service a service type
my $serviceType = "TutorialService";

# the uri of the service provider
my $authURI = "samples.jmoby.net";

# the email address of the service provider
my $email = 'your.email@domain.com';

# the url to our service cgi file
my $URL = "http://localhost/cgi-bin/getReverseEchoString.cgi";

# a small description of what our service does
my $description = "This service consumes a string of text and returns the reverse string back to the caller";

# the inputs to our service
my @input_namespaces = ();
my @input_simples = ('String', \@input_namespaces);
my @input_articles = ('my_input_string', \@input_simples);
my @all_inputs = (\@input_articles);

# the outputs to our service
my @output_namespaces = ();
my @output_simples = ('String', \@output_namespaces);
my @output_articles = ('my_reverse_string', \@output_simples);
my @all_outputs = (\@output_articles);

# register the service
my $REG = $m->registerService(
          serviceName  => $serviceName,
          serviceType  => $serviceType,
          authURI      => $authURI,
          contactEmail => $email,
          description  => $description,
          category     =>  "cgi",
          URL          =>  $URL,
          input        => \@all_inputs,
          output       => \@all_outputs,
          secondary    => undef,
      );

# where we successful?
$REG->success?print "Success!\n":print "Failure: ",$REG->message,"\n";

# END of Script

  

The above script will register the service getReverseEchoString into the registry. Further discussion on the registering of servics is beyond the scope of this tutorial. For more information on that topic, please visit the Biomoby homepage.

Service generation

Now that we have registered our service, we can now use MoSeS to generate the basis for our service.

Before we generate any code, we have to ensure that our cache (the one created when running the moses-install.pl script) is up to date.

We can update our cache by issuing the following commands:

  1. moses-generate-services.pl -u
  2. moses-generate-datatypes.pl -u

If you see a message like the following:

There was a problem updating the cache. Did you create it first?
  

Followed by an exception, use the -f option instead of the -u option.

Now we are ready to generate the basis of our service

At the command prompt, issue the following command:

  1. moses-generate-services.pl -v -c samples.jmoby.net getReverseEchoString

You should see text like the following:

Generating services from samples.jmoby.net:
Done.

Basically, we used the script moses-generate-services.pl to:

  1. automatically generate a perl module called getReverseEchoString.pm in the directory /your_home_dir/Perl-MoSeS/services/Service (if it already exists, it won't overwrite it).
    This file contains the implementation for our service and is what we edit to inject our business logic.
  2. automatically generates a cgi script called getReverseEchoString.cgi in the directory /your_home_dir/Perl-MoSeS/cgi/samples/jmoby/net/.
    This file is what we deploy on our web server that redirects cgi requests to our service to the getReverseEchoString.pm module above.

We are now ready to implement the business logic of our service!

Service implementation

Now that we are ready to implement the business logic, we will have to find, open and edit the module getReverseEchoString.pm.

MoSeS automatically created this file for you and left just the subroutine process_it for you to code your implementation. Fortunately, MoSeS provides some sample code for you to see how the datatypes are manipulated, how to get/set service notes, etc.

my $my_input_string = eval { $request->my_input_string };

The above snippet of code illustrates how MoSeS extracts the input data to our service. If you recall, when we registered our service, we stated that our service consumes a String and gave that String the name (in Biomoby speak 'ArticleName') 'my_input_string'.

If you had more than one input to a service, you would be able to access them simply by doing a

$request->articleName_of_input

Where articleName_of_input is the name that you gave the input when you registerd the service.

In the Biomoby world only datatypes that are considered primitives have values. Primitives include types such as String, Integer, Boolean, DateTime, Float, etc. In MoSeS, these values can be get/set using the method 'value'.

So in our service implementation, we have to extract the value of the String in order to reverse echo it back to a user of our service.

my $string = $my_input_string->value if defined $my_input_string;
$string = "" unless defined $my_input_string;

Now that we have our string, we can reverse it,

$string = reverse $string;

Now we can set the output of our service to have the value of our string by replacing:

# fill the response
my $my_reverse_string = new MOSES::MOBY::Data::String(
        value => "this is a value ",   # TO BE EDITED
);

with,

# fill the response
my $my_reverse_string = new MOSES::MOBY::Data::String(
        value => "$string",   # TO BE EDITED
);

That is all there is to it. Now we can test our service!

Service testing

To test the service, issue the following command:

moses-testing-service.pl Service::getReverseEchoString

This tells MoSeS to obtain the module Service::getReverseEchoString and call it. The service should output something like the following:

<moby:MOBY xmlns:moby="http://www.biomoby.org/moby">
<moby:mobyContent moby:authority="samples.jmoby.net">
<moby:serviceNotes>
<moby:Notes>Response created at Thu May 1 18:57:13 2008 (GMT), by the service 'getReverseEchoString'.</moby:Notes>
</moby:serviceNotes>
<moby:mobyData moby:queryID="job_0">
<moby:Simple moby:articleName="my_reverse_string">
<moby:String moby:id="" moby:namespace=""/>
</moby:Simple>
</moby:mobyData>
</moby:mobyContent>
</moby:MOBY>

The output is nothing special because we didn't provide the service with an input string to reverse! On the plus side, we now know that the service at least works!

Let's provide input to the service to test whether or not our functionality works as expected! Copy the following bit of XML and save it to a file (with the name input.xml). We will then use that file as input to our service.

<moby:MOBY xmlns:moby="http://www.biomoby.org/moby">
<moby:mobyContent>
<moby:mobyData moby:queryID="job_0">
<moby:Simple moby:articleName="my_input_string">
<moby:String moby:id="" moby:namespace="">I want this string reversed!</moby:String>
</moby:Simple>
</moby:mobyData>
</moby:mobyContent>
</moby:MOBY>

To test the service again, this time with some input, issue the following command:

moses-testing-service.pl Service::getReverseEchoString input.xml

This tells MoSeS to obtain the module Service::getReverseEchoString and call it with the text from input.xml. The service should output something like the following:

<moby:MOBY xmlns:moby="http://www.biomoby.org/moby">
<moby:mobyContent moby:authority="samples.jmoby.net">
<moby:serviceNotes>
<moby:Notes>Response created at Thu May 1 18:57:13 2008 (GMT), by the service 'getReverseEchoString'.</moby:Notes>
</moby:serviceNotes>
<moby:mobyData moby:queryID="job_0">
<moby:Simple moby:articleName="my_reverse_string">
<moby:String moby:id="" moby:namespace="">!desrever gnirts siht tnaw I</moby:String>
</moby:Simple>
</moby:mobyData>
</moby:mobyContent>
</moby:MOBY>

Wow, our service works as expected! We will test it once again using CGI, after we deploy it on our machine.

Service deployment

Deploying CGI based Perl MoSeS services is very straight forward!

The only thing you need to do is to tell your Web Server where the cgi script that we generated is located.

If you recall, our services' cgi script was called getReverseEchoString.cgi (the file generated using moses-generate-services.pl with the -c option)

Make a symbolic link from the cgi-bin directory of your Web Server (e.g on some Linux distributions, using Apache Web server, the cgi-bin directory is /usr/lib/cgi-bin) to the cgi-bin script.

For example:

cd /usr/lib/cgi-bin  
sudo ln -s /home/ekawas/Perl-MoSeS/cgi/samples/jmoby/net/getReverseEchoString.cgi .  

Every time that you generate a cgi service using Perl MoSeS, you will have to perform an operation similar to this one for the service that you created in order to deploy it.

Service testing using CGI

Now that the service has been deployed, you can test it using CGI with the following command:

moses-testing-service.pl -c http://localhost/cgi-bin/getReverseEchoString.cgi input.xml

When we call the script with the -c option, we tell the moses-testing-service.pl script that we would like to call our service using CGI. We then must provide the script with 1 (or an optional second) parameter:

  1. the url to the service
  2. an optional file containing the input to our service

The expected output should be very similar to the output we saw above when we tested our service:

HTTP/1.1 200 OK
Connection: close
Date: Tue, 06 May 2008 16:54:26 GMT
Server: Apache/2.2.8 (Ubuntu) PHP/5.2.4-2ubuntu5 with Suhosin-Patch
Vary: Accept-Encoding
Content-Type: text/xml; charset=ISO-8859-1
Client-Date: Tue, 06 May 2008 16:54:31 GMT
Client-Peer: 127.0.0.1:80
Client-Response-Num: 1
Client-Transfer-Encoding: chunked

<?xml version="1.0"?>
<moby:MOBY xmlns:moby="http://www.biomoby.org/moby">
 <moby:mobyContent moby:authority="samples.jmoby.net">
   <moby:serviceNotes>
     <moby:Notes>Response created at Tue May  6 16:54:31 2008 (GMT), by the service 'getReverseEchoString'.</moby:Notes>
   </moby:serviceNotes>
   <moby:mobyData moby:queryID="job_0">
     <moby:Simple moby:articleName="my_reverse_string">
       <moby:String moby:id="" moby:namespace="">!desrever gnirts siht tnaw I</moby:String>
     </moby:Simple>
   </moby:mobyData>
 </moby:mobyContent>
</moby:MOBY>

That's all there is to constructing CGI based Perl MoSeS services!