Rails is a Web-application framework that includes everything you need to create database-backed Web applications using the Model-View-Control (MVC) pattern. The most succinct definition of Action Web Service is found in its README file: "Action Web Service provides a way to publish interoperable Web service APIs with Rails without spending a lot of time delving into protocol details." In this article, you will learn how to install Rails and the Action Web Service module and get started with XML-RPC programming.
Hardware and software requirements
Any computer connected to a network capable of running Ruby should have sufficient processing power for the code presented here. Ruby V1.86 or later is required, as is RubyGems and Rails. We discuss how to install these on a machine running Microsoft® Windows®.
A Web service is a software system designed for interoperable interaction over a network. A Web service is defined with a WSDL document. Other systems interact with the Web service using SOAP messages, transferred using HTTP with an XML serialization. A Web service is an abstract resource that provides a set of functions, implemented by an agent, which sends and receives messages. A provider entity provides the functionality of a Web service with a provider agent. A requester entity uses the Web services functionality with a requester agent.
Web services implement various technologies, including XML, SOAP, and WSDL. XML is a standard format for data exchange. Web services requests and responses are sent as XML messages. The elements and attributes that may be specified in an XML document are specified in an XML schema. SOAP provides a standard framework for packaging and exchanging XML messages. WSDL is an XML document found at http://schemas.xmlsoap.org/wsdl/, which defines a namespace for describing a Web service as a set of endpoints operating on messages. A WSDL document specifies the operations (methods) provided by a Web service and the format of the XML messages.
Before discussing the Web services support in Ruby on Rails in detail, we will create a simple Web service using the Action Web Service module. First, we install Ruby on a Windows computer. The steps outlined are brief and simple (see Resources to download Ruby and Ruby on Rails, and for additional developerWorks articles describing how to use Ruby on Rails):
- For Windows users, download the Ruby Windows installer for the latest final release
(currently Ruby V1.8.6-25), and double-click on the executable. Install Ruby in the
C:/ruby directory. RubyGems, the standard Ruby package manager, which is used to
install other gems, also gets installed. Next, install Rails. From the C:/ruby
directory, the directory in which Ruby is installed, run the following command to
install Rails and dependencies:
c:/ruby>gem install rails --include-dependencies. - With the Rails 2.0 version, the Action Web Service gem is not included in the default
package. Install the
actionwebservicegem with the following command:c:/ruby>gem install actionwebservice. As of this writing,actionwebserviceV1.2.6 is the latest version. If an earlier version of Rails (pre-Rails V2.0) is used, theactionwebservicegem is included in the default package. - Create a Rails application for the Web service by entering
C:/ruby>rails webservice. - Create an apis directory in the app directory, then create a Web services API class,
HelloMessageApi, which extends theActionWebService::API::Baseclass. Store the following Ruby script tohello_message_api.rbin the app/apis directory.
Listing 1. Web services API classHelloMessageApiclass HelloMessageApi < ActionWebService::API::Base api_method :hello_message, :expects => [{:firstname=>:string}, {:lastname=>:string}], :returns => [:string] end - Create a controller script, which defines a controller class:
HelloMessageController. Copy the following Ruby code to the controller script and save the controller script,hello_message_controller.rb, in theapp/controllersdirectory.
Listing 2. Controller classHelloMessageControllerclass HelloMessageController < ApplicationController web_service_api HelloMessageApi web_service_dispatching_mode :direct wsdl_service_name 'hello_message' web_service_scaffold :invoke def hello_message(firstname, lastname) return "Hello "+ firstname +" "+lastname end end - Start the WEBrick Web server by entering
C:/ruby/webservice>ruby script/server. - Display the WSDL file for the Web service with the URL
http://localhost:3000/hello_message/wsdl.
Figure 1. Web services WSDL
- Invoke the Web service with
http://localhost:3000/hello_message/invoke. The API methods for the Web service will be displayed. Select theHelloMessagemethod.
Figure 2. Invoking the Web service
- To test the Web service, specify a first name and a last name, then click Invoke.
Figure 3. Invoking a Web services method
- The return value is output, as well as the request XML and response XML.
Figure 4. Output from the Web service
Let's discuss the Web service in detail. The Web services API class
defines the methods the Web service provides. The example API class defines the hello_message method, which takes two parameters of type string and returns a string value. An API method is defined with the
api_method method of the ActionWebService::API::Base class. The WSDL for the Web service is
created from the API class. The Web services API class extends the ActionWebService::API::Base class. The controller class contains the
code the Web service makes available to a client. The web_service_api option specifies the API definition class. The web_service_dispatching_mode option specifies the dispatching method
where remote callers send their invocation methods, the endpoint URLs, and how the
method invocation is routed to the object that implements the method.
With the direct dispatching mode, method invocations are made directly to the
controller. The API method implementations are defined in the controller class as public
instance methods. The direct mode is the default mode. The wsdl_service_name option specifies the Web service name. The web_service_scaffold option generates a Web services scaffolding for
method invocations. The Web services scaffolding is similar to the Active Record's
scaffolding. The invoke method specified in the example Web service lists all the
methods in all the APIs attached to the controller. The hello_message action in the controller class is available to clients for method invocation.
In the previous example, the Web services API class is HelloMessageApi. The Web service API class extends the ActionWebService::API::Base class and specifies the methods
to be made available for an API in a Web service. Some of the methods of the class are discussed below.
Table 1. ActionWebService::API::Base Methods
| Method | Description |
|---|---|
| api_method(name, options={}) | Specifies an API method; the options are :expects-Signature for method input parameters, :returns-Signature for return value, :expects_and_returns-Signature for input parameters and return values |
| api_method_name(public_name) | Specifies a service method name for a public method name |
| api_methods() | Specifies a hash of service methods on this API |
| has_public_api_method?(public_name) | Specifies whether a public method has a corresponding service method on this API |
| soap_client(endpoint_uri, options={}) | Specifies a SOAP client |
| xmlrpc_client(endpoint_uri, options={}) | Specifies an XML RPC client |
The procedure to define a API class is as follows:
- Determine which methods are to be made available on the API.
- Create a class that extends the
ActionWebService::API::Baseclass. - Define the methods using the
api_methodoption, including the method signature.
Dispatching is the distribution of method invocations on a Web service. A dispatching approach refers to where remote callers send their invocation messages and how the method invocations are routed to the method implementation object. An API is implemented based on the dispatching approach. Three dispatching approaches are available:
- Direct
- Delegated
- Layered
With the direct dispatching approach, the API definition class is attached to the
controller class, and the API methods are implemented in the controller class as public
instance methods. As in the example application discussed earlier, the direct
dispatching is specified as web_service_dispatching_mode
:direct.
The direct dispatching approach is the default approach. With the direct dispatching
approach, a controller class may implement only one API. The endpoint URL for a Web
service with direct dispatching is of the http://SERVER/CONTROLLER_NAME/api
format.
The endpoint URL for the example Web service discussed earlier is http://localhost:3000/hello_message/api, as
specified in the service element of the WSDL document.
Listing 3. Endpoint URL
<service name="hello_messageService"> <port name="hello_messageHelloMessagePort" binding="typens:hello_messageHelloMessageBinding"> <soap:address location= "http://localhost:3000/hello_message/api" /> </port> </service> |
In the direct dispatching mode, the web_service_api option
may be omitted if the API definition class is of the same name as the controller class
and is stored in the app/apis directory in a Ruby file of
the format apiclass_api.rb. In the example application
discussed earlier, the web_service_api option is not
required in the controller class as the API class is stored in the hello_message_api.rb. The procedure to develop an Action Web Service
Web service using the direct dispatching approach is as follows:
- Define an API class, a class that extends the
ActionWebService::Baseclass, and define the API methods. - Attach the API Web service class to a controller class using the
web_service_apioption. - Set the dispatching mode to "direct" with
web_service_dispatching_mode :direct. - Implement the API methods in the controller class as public instance methods.
- Test the Web service by adding scaffolding to the controller class.
A limitation of the direct dispatching approach is that a
controller class may implement only one API. In the delegated dispatching
approach, a controller class may implement more than one API. We shall discuss delegated dispatching with an example.
Define two API classes: HelloMessageApi and DeveloperApi. Store the HelloMessageApi
class in hello_message_api.rb Ruby script in the app/apis directory. The HelloMessageApi
class defines a hello_message API method that takes two
string parameters, firstname and lastname, and returns a string value. The hello_message_api.rb script is shown below.
Listing 4. hello_message_api.rb
class HelloMessageApi < ActionWebService::API::Base
api_method :hello_message, :expects =>
[{:firstname=>:string},
{:lastname=>:string}], :returns => [:string]
end
|
Store the DeveloperApi class in the developer_api.rb Ruby script in the app/apis directory. The DeveloperApi
class defines a developer method that takes two string
parameters and returns a string value. The developer_api.rb
script is shown below.
Listing 5. developer_api.rb
class DeveloperApi < ActionWebService::API::Base
api_method :developer, :expects =>
[{:firstname=>:string},
{:lastname=>:string}], :returns => [:string]
end
|
Create a service class for each API class. A service class extends the ActionWebService::Base class. The service class implements the
methods defined in the API class. The API class is attached with the service class
using the web_service_api option. The HelloMessageService class implements the HelloMessageApi API class. Store the HelloMessageService service class in the app/models
directory as Ruby script hello_message_service.rb. The hello_message_service.rb script is shown below.
Listing 6. hello_message_service.rb
class HelloMessageService < ActionWebService::Base
web_service_api HelloMessageApi
def hello_message(firstname, lastname)
return "Hello "+ firstname +" "+lastname
end
end
|
Similarly, create a service class, DeveloperService, for the
DeveloperApi API class. The Ruby script for the DeveloperService class is stored in the app/models directory as developer_service.rb. The developer_service.rb script is shown below.
Listing 7. developer_service.rb
class DeveloperService < ActionWebService::Base
web_service_api DeveloperApi
def developer(firstname, lastname)
return "This Web service is developed by "+ firstname +"
"+lastname
end
end
|
Create a controller class for the service classes. Set the dispatching mode to
"delegated" with the following option setting: web_service_dispatching_mode :delegated. Attach the service classes
to the controller class using the web_service option. For
example, the HelloMessageService class is attached to the
controller class with the following declaration: web_service :hello_message, HelloMessageService.new.
Hello_message is a Web service that represents the HelloMessageService class. To test the Web service, add scaffolding to
the controller class with the web_service_scaffold option.
web_service_scaffold :invoke. Store the controller class in
the app/controllers directory. The controller script, delegated_controller.rb, is shown below.
Listing 8. delegated_controller.rb
class DelegatedController < ApplicationController web_service_dispatching_mode :delegated web_service :hello_message, HelloMessageService.new web_service :developer, DeveloperService.new web_service_scaffold :invoke end |
The controller class does not have to be named DelegatedController. Next, we will test the Web service. Start the
WEBrick Web server if it is not already started: C:/ruby/helloservice>ruby script/server. Invoke the Web service
listing of methods with the URL http://localhost:3000/delegated/invoke.
API methods for all the API service classes specified in the controller class get listed.
Figure 5. Invoking a delegated Web service
Compared to the direct dispatching approach, more than one API class may be attached to the controller class using the service classes. The procedure to develop a Action Web Service Web service using the delegated approach is as follows:
- Define API classes to be implemented by the Web service.
- Create a service class, a class that extends the
ActionWebService::Baseclass, for each of the API classes. Attach the API class to the service class with theweb_service_apioption. - Implement the API methods in the service class as public instance methods.
- Create a controller class and set the dispatching mode to "delegated."
- Attach the service classes to the controller class with the
web_service option. - Test the Web service by generating a scaffolding for the Web service using the
web_service_scaffoldoption.
The layered dispatching approach procedure is similar to the delegated
dispatching approach, except for the following declaration: web_service_dispatching_mode :layered. Each method invocation is
prefixed with the service name in the servicename.methodname format. A layered
dispatching approach Web service may also be tested using scaffolding, generated with
the web_service_scaffold option.
Action Web Service provides some client classes for accessing remote Web services. A
remote Web service may be accessed from inside a controller using the web_client_api helper function or directly using an instance of the
ActionWebService::Client::Soap or ActionWebService::Client::XmlRpc class. In this section, we
create a Action Web Service Web service, and access the Web service using the web_client_api function and the direct
instance method invocation. We need to create two separate Rails applications
— one for the Web service and the other for the client. Create a Rails
application for the Web service by entering C:/ruby>rails
helloservice.
Create a Hello Web service with a HelloApi API class and a getMsg API
method using the web_service script generator:
C:/ruby/helloservice>ruby script/generate web_service Hello getMsg |
A HelloApi API class gets created in the apis directory as
Ruby script hello_api.rb. A hello_controller.rb controller script gets created in the controllers
directory. The HelloController controller class includes a
getMsg controller action. The controller class also specifies
the wsdl_service_name, the Web service name. The WSDL for a
Web service is available when the Web service is run. Modify the controller script to
specify the web_service_api option and specify the
scaffolding with the web_service_scaffold option. The web_service_api option maps the controller to the API class. Modify
the getMsg controller action to take a string parameter and
return a string value. The getMsg method implements the
getMsg method in the API class. The modified controller script is shown below.
Listing 9. hello_controller.rb
class HelloController < ApplicationController wsdl_service_name 'Hello' web_service_api HelloApi web_service_scaffold :invoke def getMsg(name) "Hello "+ name end end |
Modify the HelloApi API class to add a parameter and a
return value to the getMsg method signature. The HelloApi class is shown below.
Listing 10. HelloApi
class HelloApi < ActionWebService::API::Base api_method :getMsg, :expects => [:name=>:string], :returns => [:string] end |
Next, we will test the Web service. Start the Web service with the following command from the Web service directory: C:/ruby>webservice>ruby script/server. Invoke the Web service using the URL http://localhost:3000/hello/invoke. The API methods for the Web service get listed. Click on the GetMsg method.
Figure 6. Invoking a Web service scaffolding
An input field for name gets displayed. You may also select the protocol: SOAP or XML RPC. Specify a value in the Name field and click Invoke.
Figure 7. Invoking a Web service method
The getMsg Web services method gets invoked with the name
parameter value as "Steve," and the return value gets output. Also, the request XML and response XML messages display.
Figure 8. Return value from the Web service
Next, we create a Rails application for the client using C:/ruby>rails helloadmin. Create an apis directory in the app
directory of the helloadmin Rails application and copy the
hello_api.rb script from the helloservice Rails application to the apis directory. Create a controller script for the Web service client:
C:/ruby/helloadmin>ruby script/generate controller helloadmin getMsg |
A HelloadminController controller class consisting of a
getMsg controller action gets created. Access the Web
service API from the controller class using the web_client_api function:
web_client_api :hello, :xmlrpc, "http://localhost:3001/hello/api" |
The web_client_api(name, protocol, endpoint_uri, options={})
method creates a protected method specified with name parameter using the specified
protocol to communicate with the specified endpoint URI. We have created a
hello method using the xmlrpc protocol to connect with the
endpoint URI http://localhost:3001/hello/api. We run
the Hello Web service on port 3001 and access the Web
service with a client on port 3000. Modify the getMsg
controller action to create a variable for the output of the Web services method
invocation. Using the hello method created with web_client_api, invoke the getMsg method
of the Hello Web service with a name parameter as input to the method. We define the name parameter value in an index.rhtml view
template. The controller script helloadmin_controller.rb is
shown below.
Listing 11. helloadmin_controller.rb
class HelloadminController < ApplicationController
web_client_api :hello, :xmlrpc, "http://localhost:3001/hello/api"
def getMsg
@service_output= hello.getMsg(params[:name])
end
end
|
The Hello Web service may also be accessed directly using
an instance of the ActionWebService::Client::Soap or ActionWebService::Client::XmlRpc class. The helloadmin_controller.rb script may also be represented using an
instance of the ActionWebService::Client::Soap class, as
shown below.
Listing 12. helloadmin_controller.rb
class HelloadminController < ApplicationController
def getMsg
hello_client = ActionWebService::Client::Soap.new(HelloApi,
"http://localhost:3001/hello/api")
@service_output= hello_client.getMsg(params[:name])
end
end
|
Create an index.rhtml view template in the views/helloadmin directory and add a form with an input field,
"name," in the RHTML template. When the form is submitted, the getMsg method of the Helloadmin
controller is invoked. View template index.rhtml is shown below.
Listing 13. index.rhtml
<html>
<head>
<title>Hello Web Service</title>
</head>
<body>
<h1>Hello Web Service</h1>
<p>
This Rails application tests a Web service.
</p>
<%= start_form_tag :action=> 'getMsg' %>
<p><label>Name</label><br/>
<%= text_field 'name', '' %></p>
<%= submit_tag "Get Message" %>
<%= end_form_tag %>
</body>
</html>
|
Modify the getMsg.rhtml view template to output the value of
the variable @service_output, which is defined in the Helloadmin controller class's getMsg
method. The getMsg.rhtml view template is shown below.
Listing 14. getMsg.rhtml
<html>
<head>
<title>Hello Web Service</title>
</head>
<body>
<h1>Hello Web Service </h1>
<p>
</p>
<p>
<%= @service_output %>
</p>
</body>
</html>
|
Next, we will test the Web service, Hello, using the client Rails application. Start the Web service on port 3001 with the following command from the helloservice directory:
C:/ruby/helloservice>ruby script/server --port=3001 |
Start the client Rails application on the default port 3000 from the helloadmin directory:
C:/ruby/helloadmin>ruby script/server |
The example application demonstrates accessing a Web service from a protocol client. Invoke the index controller action of the Helloadmin controller with the URL http://localhost:3000/helloadmin/index. The index.rhtml view template gets displayed. Specify a name value and click Get Message.
Figure 9. Testing a Web service with a protocol client
The getMsg method of the Helloadmin controller gets invoked. Using the hello method, which is defined using the web_client_api option, the Hello Web service is accessed, and the getMsg method
of the Web service is invoked. The output from the Web service is displayed in the getMsg.rhtml view template.
Figure 10. Output from the Web service
The procedure to access a Web service using a protocol client is as follows:
- Create a Rails application for a Web service.
- Create a Web service.
- Define the API method or methods and implement the method in the controller class.
- Create a Rails application for the protocol client.
- Define the API class and the API method or methods.
- Access the Web service from the client application controller using the
web_client_apioption, an instance of theActionWebService::Client::Soap, orActionWebService::Client::XmlRpc. - Implement the API methods in the client controller class.
- Start the Web service on port 3001.
- Start the client application on port 3000.
- Invoke the API methods from an RHTML view template and output the Web service output to another RHTML view template.
Although Rails V2.x includes the REST-based ActiveResource gem in the default bundle instead of the SOAP-based Action Web Service gem, the SOAP-based Web services have their advantages, too (see Resources). In this article, we discussed how to use the Action Web Service gem to create SOAP and XML-RPC-based Web services, and presented several examples to help you get started with this technology.
Learn
- Learn more about Action Web Service — Serving APIs on Rails in the Rails Framework Documentation.
- Learn about Web Services Architecture in this W3C Working Group note.
- Learn about WSDL in this W3C Working Group note.
- "Make Ruby on Rails easy with RadRails and Eclipse" is a tutorial showing how to use Ruby on Rails in Eclipse.
- "An introduction to Ruby on Rails for DB2 developers" is an introduction to Ruby on Rails for DB2 developers.
- "Create a Web service with Ruby on Rails for integration with WebSphere Process Server" shows how to use a Web service to facilitate the communication between a Ruby on Rails client and an SCA component running on WebSphere® Process Server.
- "Create a Web Service that receives SOAP attachments with Rational Application Developer" describes how to use IBM® Rational® Application Developer to create a Web service that can receive a SOAP message containing attachments, in addition to the normal content contained in the body of the message.
- "Fast-track your Web apps with Ruby on Rails" is an introduction to Ruby on Rails.
- "Web Services, Part 1: SOAP vs. REST" compares and contrasts these two approaches to developing Web services.
- To listen to interesting interviews and discussions for software developers, check out developerWorks podcasts.
- Stay current with developerWorks' Technical events and webcasts.
- Check out upcoming conferences, trade shows, webcasts, and other Events around the world that are of interest to IBM open source developers.
- Visit the developerWorks Open source zone for extensive how-to information, tools, and project updates to help you develop with open source technologies and use them with IBM's products.
- Watch and learn about IBM and open source technologies and product functions with the no-cost developerWorks On demand demos.
Get products and technologies
- Download Ruby and Ruby on Rails from Ruby on Rails.org.
- Innovate your next open source development project with IBM trial software, available for download or on DVD.
- Download IBM product evaluation versions, and get your hands on application development tools and middleware products from DB2®, Lotus®, Rational®, Tivoli®, and WebSphere®.
Discuss
- Participate in developerWorks blogs and get involved in the developerWorks community.
Deepak Vohra (dvohra09@yahoo.com) is a Web Developer, a NuBean Consultant, and a Sun Certified Java 1.4 Programmer. You can reach him at dvohra09@yahoo.com.




