Ruby Web Services

The basic point of distributed programming is to let computers communicate between themselves. The simplest and most common form of distributed programming is the web service. Web services work on top of HTTP: they generally involve sending an HTTP request to a certain URL (possibly including an XML document), and getting a response in the form of another XML document. Rather than showing this document to an end user the way a web browser would, the web service parses the XML response document and does something with it. Web services work well when there's a server with some interesting data and many clients who want it.

From a high-level view, web service implementations can be broken down into two categories: servers and clients. Most web services are based on one of three architectures: Representational State Transfer (REST), Simple Object Access Protocol (SOAP), or Extensible Markup Language Remote Procedural Calls (XML-RPC). REST is HTTP; XML-RPC and SOAP are protocols that run on top of HTTP. XML-RPC isn't used much nowadays.

Writing a RubyLearning SOAP server and client

Ruby's built-in SOAP library (implements both the client and server sides of the SOAP protocol) handles the low-level details for you, leaving you free to focus on using the results in your program. To write the SOAP service, we use Hiroshi Nakamura's soap4r library. It is part of the Ruby standard library and implements SOAP version 1.1 (the soap4r library is not included in Ruby 1.9).

Let's say that RubyLearning wants to host a SOAP-based web service (we are going to build a trivial one just to show how it is done) using a standalone server (SOAP::Standalone Server that is, not as part of a Rails application).

Building our own SOAP server (program p072soapserver.rb) really requires only three simple steps:

Subclass the SOAP::Standalone Server class. In the initialize method, register the methods you want to expose and the arguments they should take. Here we expose a method sayhelloto that expects one parameter, username:

require 'logger' require 'soap/rpc/standaloneServer' class MyServer < SOAP::RPC::StandaloneServer def initialize(* args) super add_method(self, 'sayhelloto', 'username') # create a log file @log = Logger.new("soapserver.log", 5, 10*1024) end def sayhelloto(username) t = Time.now @log.info("#{username} logged on #{t}") "Hello, #{username} on #{t}." end end server = MyServer.new('RubyLearningServer','urn:mySoapServer','localhost',12321) trap('INT') {server.shutdown} server.start

The above example runs on port 12321 on localhost (you could host it on your own domain too). It's name is 'RubyLearningServer' and its namespace is 'urn:mySoapServer'. We've now built a complete SOAP server. It uses the SOAP StandaloneServer and hosts one simple sayhelloto method that can be accessed at http://127.0.0.1:12321/ with a namespace of "urn:mySoapServer". We trap interrupt signals so that we can stop our server from the command line.

To test your service, start the above server in one Ruby session and then use the simple script (p073prclient.rb) below in another Ruby session to call the method it exposes:

# p073prclient.rb require 'soap/rpc/driver' driver = SOAP::RPC::Driver.new('http://127.0.0.1:12321/', 'urn:mySoapServer') driver.add_method('sayhelloto', 'username') puts driver.sayhelloto('RubyLearning')

The output is:

>ruby p073prclient.rb Hello, RubyLearning on Sun Nov 25 14:57:54 +0530 2007. >Exit code: 0

Note: The Ruby Logo is Copyright (c) 2006, Yukihiro Matsumoto. I have made extensive references to information, related to Ruby, available in the public domain (wikis and the blogs, articles of various Ruby Gurus), my acknowledgment and thanks to all of them.