Wednesday, March 21, 2007

Web Services Made Easy with Ruby

It's easy to develop Web services using Ruby. This article looks at how to develop a Web service client to access the Web services that are hosted in the Internet and how to develop a Web service with simple steps using Ruby.

An Overview
Ruby is the interpreted scripting language invented by Yukihiro Matsumoto for quick and easy object-oriented programming and is more popular in Japan than in other countries. Ruby's open-source nature makes it free for anyone to use. All data structures in Ruby are objects, but you can add methods to a class or instance of a class during runtime. Because of this, any instance class can behave differently from other instances of the same class. Ruby's dynamic typing nature doesn't require explicit declaration of variable types. It features a true mark-and-sweep garbage collector that cleans all Ruby objects without needing to maintain a reference count. (See www.ruby-lang.org for the complete features of Ruby.) The following libraries are developed with Ruby:
# Ruby/DBI: To access different databases
# Ruby/LDAP: To search and operate on entries in the LDAP
# XSLT4R: For XSL transformation
# XMLRPC4R: For writing and accessing Web services
# SOAP4R: For writing and accessing Web services

SOAP Programming Using Ruby
SOAP4R is the implementation of Simple Object Access Protocol for Ruby developed by Hiroshi Nakamura. SOAP4R depends on the XML processor, http-access, logging, and date-time packages. (To install SOAP4R and its dependencies refer to its home page at www.jin.gr.jp/~nahi/Ruby/SOAP4R.)

Develop SOAP4R clients
The SOAP::Driver class provides support for writing SOAP client applications using Ruby. I'll explain how to use this class in order to develop the SOAP client. To invoke a SOAP Service the client should know the URL of the SOAP Service, namespace of the service methods, and the names of the service methods and their parameters. With this information let's develop a SOAP client in Ruby.

I've chosen a "SendEmail" Web service that is listed in Xmethods' Web services list. The client we're developing invokes a service named SendEmail to send an e-mail message to any mail address (see Listing 1).

In the first line I load the feature "soap/ driver", which implements the SOAP::Driver class. Then I define four constants like NAMESPACE, URL, SOAPACTION, and HTTP_ PROXY, which are required to create an instance of SOAP::Driver class by calling its new method.

driver = SOAP::Driver.new(log, logId, namespace ,
endpoint, httpProxy, soapAction )
Where
namespace = namespace to use for RPC calls
endpoint = URL of the SOAP service
httpproxy = to specify the proxy server,
instead of direct connection to SOAP server
soapaction = value for SOAPAction field of the SOAP Header

After creating an instance of the driver class, call the addMethod method passing the name of the SOAP service method and its parameters' names. SOAP method parameters are often not taken into account on the SOAP server side but it is important to know the order of the parameters that were passed to the service.

The SOAP::Driver class has two methods to add service methods:

SOAP::Driver.addMethod(name, *paramArg)
SOAP::Driver.addMethodWithSOAPAction(name, soapaction, *paramArg)
Where name = the name of the remote procedure
soapaction = soap action header to be used instead
of the default one specified on SOAPDrivers newmethod
paramArg = to specify the names and modes of the remote
procedures parameters. The parameter modes are input parameter,
output parameter or in out parameter.

After adding the service method to the Driver class, invoke it by passing the parameters with values.

SOAPDriver::ServiceMethod( *paramvaluesArg)

Where ServiceMethod is the name of the remote procedure, that was added using addMethod API.

The Web services client is now ready for testing. Test the client using the following command:

ruby SendEmail.rb

Just three steps are needed to develop a Web services client using SOAP4R.

Develop SOAP4R Services
SOAP4R supports the following servers:
# CGI/Fast CGI-based servers (SOAP::CGI Stub)
# Stand-alone server (SOAP::Standalone Server)

Now let's look at how to develop services using the stand-alone server. I'll develop a temperature conversion service that converts the temperature from Celsius to Fahrenheit (see Listing 2).

Develop a class called Temperature_ Conversion_Server and inherit from SOAP:: StandaloneServer, which inherits from SOAP:Server.

class Temperature_Conversion_Server
< SOAP::StandaloneServer
# declare methods
# define methods
end

Declare your service methods by overriding the methodDef method in the StandaloneServer. For example, convert_to_ Fahrenheit, which takes degrees as input parameters:

def methodDef addMethod(self,
'convert_to_Fahrenheit', 'degrees' )
end

The methodDef method is implicitly called from SOAP::Server's initialize method, which exposes one of the following two ser-vice methods.

Class Server < Devel::Application
def addMethod( receiver, methodName, *paramArg )
end

def addMethodWithNS( namespace, receiver, methodName, *paramArg )
end
end
Where
Receiver = the object which contains the methodName method.
Use "self" if the service method is in the same class
methodName = the name of the method that is called through an RPC request
paramArg = to specify the parameter names and parameter modes
namespace = in order to specify the namespace for the method.
Use this if you want different namespace for each method.

After you declare the service method, define it as:

def convert_to_Fahrenheit( degrees )
temp = (9*degrees + 160)/5
return temp
end

The StandaloneServer constructor looks like:

class StandaloneServer < Server
def initialize( appName, namespace, host = "127.0.0.1", port = 8080 )
end
appName - to specify the applications log Id paramters
namespace - Namespace parameters apply to default namespace
for all the service methods.app host to specify the server
host by default it is local host i.e "127.0.0.1",
port to specify the port number for the server ,
by default it is 8080.

Create an instance of the StandaloneServer class and start the server:

myServer = Temperature_Conversion_Server.new('ConversionServer',
'urn:ruby:conversionservice', 'localhost', 8080)
myServer.start

The temperature conversion service is now ready for testing. Start the server using the following command:

ruby ConversionServer.rb

Develop a Web service client application to test the Temperature conversion service (see Listing 3) and test the service using the command:

ruby ConversionClient.rb

In order to monitor the Web service traffic (i.e, SOAP Request and SOAP Response), run the monitor application, which is included with the XML-RPC samples.

Conclusion
It's easy to develop Web services with Ruby. SOAP4R supports logging for the client side and server side as well and supports the user-defined data types. SOAP4R provides the ability to customize the mapping between the Ruby and the SOAP Types. It has good support for SOAP Parameters like IN, OUT, INOUT, and return, and supports WSDL as well. Refer to the samples that come with SOAP4R for more information.

References
# Ruby: www.ruby-lang.org/en/
# SOAP4R: www.jin.gr.jp/~nahi/Ruby/SOAP4R

No comments: