Web Service Backend Tutorial

ApiService Tutorial

Introduction

The objective of this tutorial is to provide to the user a simple guideline to create a basic Web Service with Apache, Perl and MySql on a Windows platform.

Web Services is a technology that involves several standards such as WSDL, XML Schema, SOAP, among others. The purpose of this document is not to give a deep explanation about all technologies used, but rather a general overview of the integration of those technologies.

After the completion of this tutorial the reader should be able to run an Api service locally in her/his computer.

Standards

As stated earlier, there are several standards which Web Services make use of. The following list gives a general description about the main standards that the Api Service uses. (For a more complete explanation see the "Reference" section in the appendix)

Furthermore, in order to develop the Api Service; basic knowledge of Apache, Perl and SQL is required.

Software

This service was developed on the Windows platform, but remarks about porting to Linux/Unix are specified in section 7.1.
The following software is required to run the service:

Configuration

Apache

In order to run the perl scripts the CGI module needs to be active. A line like the following should be included in the "httpd.conf" configuration file:
LoadModule cgi_module modules/mod_cgi.so

Another module that will be required is alias which is used to map the "cgi-bin" directory:
LoadModule alias_module modules/mod_alias.so

The configuration should contain a section specifying the path to map the "cgi-bin" directory:

<IfModule alias_module>
ScriptAlias /cgi-bin/ "C:/my.bindows.distribution/samples/apiservice/"
</IfModule>

MySql

The service will require to connect to an existing "ApiService" database. It will also require to have reading and writing permissions into the "classes" table. However, the database name, the user name and the password can be configured in the "ApiService.pm" file as explained later.
The ApiService database template is found in the "ApiService.sql" file.

Perl

The Perl modules that will be required are:

Structure

Components

The files included in the ApiService application are listed below:

Description

Figure 1 gives an overview of the service components interactions.

First, the client application calls the "ApiService.pl" script to retrieve the WSDL file. "ApiService.pl" in turn just reads the WSDL file and sends it back to the client application. Second, the client application parses the WSDL file and is able to invoke the available services and operations exposed by the ApiService with the required format. The messages have a SOAP format, which makes the backend to understand them.

Thereafter, the client application invokes an operation by sending a SOAP message to "ApiServiceSoap.pl". This script is only used for receiving and parsing the SOAP message to convert it into a Perl structure that "ApiServiceSoap.pm" can handle.

"ApiServiceSoap.pm" could directly process the request, but since this script is accessed without any restriction, the user could send a valid SOAP message invoking inappropriate methods, such as connectToDatabase. Therefore, "ApiServiceSoap.pm" forwards the message to "ApiService.pm" which has private and public methods to process the request.

Finally, the message arrives to "ApiService.pm" which interacts with the database performing the operation that the user wants.

Api Service structure

Figure 1: Api Service structure

It is worth noting that the file "ApiService.wsdl" could be located anywhere, not necessarily in the same directory as the scripts. However, in this tutorial we kept the files together for the sake of clarity. If the WSDL file is located somewhere else, then the script "ApiService.pl" could be removed.

Functionality

Operations

The following operations have been implemented in the ApiService:

Analysis

In order for the Web Service to work correctly it is necessary to have synchronization between the WSDL description and the operations in the Perl scripts. For example, analyzing the WSDL description of the getClasses operation:

<wsdl:operation name="getClasses">
	<wsdl:documentation>
	...
	</wsdl:documentation>
	<wsdl:input name="getClasses" message="tns:getClasses"/>
	<wsdl:output name="getClassesResponse" message="tns:getClassesResponse"/>
</wsdl:operation>
			
We see that the operation requires as input a message type getClasses and that it returns as output a message type getClassesResponse which are defined as <wsdl:message> sections:
<wsdl:message name="getClasses">
	<wsdl:part name="parameters" type="tns:getClasses"/>
</wsdl:message>
<wsdl:message name="getClassesResponse">
	<wsdl:part name="return" type="tns:getClassesResponse"/>
</wsdl:message>
			
Each of these messages in turn have a type which is defined in the <wsdl:types> section in a schema:
<xsd:complexType name="getClasses">
	<xsd:sequence>
		<xsd:element minOccurs="0" maxOccurs="1" name="nMaxClasses" type="xsd:integer"/>
	</xsd:sequence>
</xsd:complexType>

<xsd:complexType name="getClassesResponse">
	<xsd:all>
		<xsd:element minOccurs="1" maxOccurs="1" name="nStatus"  type="xsd:integer"/>
		<xsd:element minOccurs="0" maxOccurs="1" name="nClasses" type="xsd:integer"/>
		<xsd:element minOccurs="0" maxOccurs="1" name="sClasses" type="xsd:string"/>
	</xsd:all>
</xsd:complexType>
			
We can notice that the type getClasses is composed by a sequence element with one child element: nMaxClasses. Furthermore, we can see that this element is optional, as minOccurs is an integer type that is equal to 0. These features of nMaxClasses are synchronized with the "ApiService.pm" script at:
# if we received a nMaxClasses parameter use it
# to limit the number of rows retrieved
	$sQuery .= " LIMIT $rhParams->{ nMaxClasses }"
		if( $rhParams->{ nMaxClasses } );
			
Where we can see that if the parameter nMaxClasses exist then the $sQuery string will append a LIMIT restriction. Similarly, we can see that for the type getClassesResponse we have an all element with three children elements: nStatus, nClasses and sClasses, where the last two elements are optional. In the perl script we can match these features at:
# return result object
	return {nStatus => 1, nClasses => $nClasses, sClasses => "$sClasses"};
}
else
{
# we couldn't connect to the database, return an error
	return {nStatus => 0};
}
			
Where the elements nClasses and sClasses are absent in case of an error.

Customizing

Porting to Unix/Linux

The ApiService can be ported to Unix/Linux with the following considerations:

Those are the most common errors when porting to Unix/Linux.

Deploying

If the service needs to be deployed then the targetNamespace in the WSDL file should be changed from localhost to my.domain.com, as well as all other occurrences of the word localhost.

Changing Complex Types from "All" to "Sequence"

Changing the element from all to sequence requires that the object return by the operation has the children elements ordered, this could be done through the package Tie::IxHash as in the following example:

use Tie::IxHash;
...
tie my %hRes, 'Tie::IxHash',
	nStatus	 => $nStatus,
	nClasses => $nClasses,
	sClasses => $sClasses;
return \%hRes;
			
More information could be found at: Tie::IxHash.

Database account

If the user needs to change the database name, the user account or the password to access the database, the changes need to be done in the file "ApiService.pm" at:

our $rhSettings =
{
	database => 'ApiService',
	user => 'NewApiServiceUser',
	pass => 'NewApiServicePass'
};
			

Limitations

This application has some security limitations, handling all of them is out of the scope of this document but the most common are mentioned in the following list:

Further development

The user of this tutorial should be able to experiment and add more operations as well as the necessary messages and types for them.

Some useful Perl libraries worth checking are JSON are XML::Parser.

Appendix

Reference

Web Service

WSDL

WSDL binding style/use

Schema