Create Web services with Ruby on Rails and Action Web Service

Get started with SOAP and XML-RPC programming with the Rails Action Web Service gem

The Action Web Service module implements Web services functionality in Ruby on Rails. Action Web Service creates server-side support for SOAP and XML-RPC Web service protocols. You can declare and publish APIs using Action Web Service.

Deepak Vohra, Web Developer, Independent

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.


developerWorks Contributing author
        level

04 November 2008

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®.

How Web services work

Frequently used acronyms

  • API— Application program interface
  • HTML— Hypertext Markup Language
  • HTTP— Hypertext Transfer Protocol
  • REST— Representational State Transfer
  • RHTML— Ruby code mixed with HTML templates
  • SOAP— Simple Object Access Protocol
  • UI— User interface
  • WSDL— Web Services Description Language
  • XML— Extensible Markup Language
  • XML-RPC— Remote Procedure Calling using HTTP and XML

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.


Creating a Web service

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):

  1. 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.
  2. With the Rails 2.0 version, the Action Web Service gem is not included in the default package. Install the actionwebservice gem with the following command: c:/ruby>gem install actionwebservice. As of this writing, actionwebservice V1.2.6 is the latest version. If an earlier version of Rails (pre-Rails V2.0) is used, the actionwebservice gem is included in the default package.
  3. Create a Rails application for the Web service by entering C:/ruby>rails webservice.
  4. Create an apis directory in the app directory, then create a Web services API class, HelloMessageApi, which extends the ActionWebService::API::Base class. Store the following Ruby script to hello_message_api.rb in the app/apis directory.
    Listing 1. Web services API class HelloMessageApi
    class HelloMessageApi < ActionWebService::API::Base
      api_method :hello_message, :expects => [{:firstname=>:string}, 
    {:lastname=>:string}], :returns => [:string]
    
    
    end
  5. 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 the app/controllers directory.
    Listing 2. Controller class HelloMessageController
    class 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
  6. Start the WEBrick Web server by entering C:/ruby/webservice>ruby script/server.
  7. Display the WSDL file for the Web service with the URL http://localhost:3000/hello_message/wsdl.
    Figure 1. Web services WSDL
    Web services WSDL
  8. Invoke the Web service with http://localhost:3000/hello_message/invoke. The API methods for the Web service will be displayed. Select the HelloMessage method.
    Figure 2. Invoking the Web service
    Invoking the Web service
  9. To test the Web service, specify a first name and a last name, then click Invoke.
    Figure 3. Invoking a Web services method
    Invoking a Web services method
  10. The return value is output, as well as the request XML and response XML.
Figure 4. Output from the Web service
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.


Web services API class

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
MethodDescription
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:

  1. Determine which methods are to be made available on the API.
  2. Create a class that extends the ActionWebService::API::Base class.
  3. Define the methods using the api_method option, including the method signature.

Dispatching

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:

  1. Direct
  2. Delegated
  3. Layered

Direct dispatching

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:

  1. Define an API class, a class that extends the ActionWebService::Base class, and define the API methods.
  2. Attach the API Web service class to a controller class using the web_service_api option.
  3. Set the dispatching mode to "direct" with web_service_dispatching_mode :direct.
  4. Implement the API methods in the controller class as public instance methods.
  5. Test the Web service by adding scaffolding to the controller class.

Delegated dispatching

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
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:

  1. Define API classes to be implemented by the Web service.
  2. Create a service class, a class that extends the ActionWebService::Base class, for each of the API classes. Attach the API class to the service class with the web_service_api option.
  3. Implement the API methods in the service class as public instance methods.
  4. Create a controller class and set the dispatching mode to "delegated."
  5. Attach the service classes to the controller class with the web_service option.
  6. Test the Web service by generating a scaffolding for the Web service using the web_service_scaffold option.

Layered dispatching

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.


Protocol clients

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
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
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
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
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
Output from the Web service

The procedure to access a Web service using a protocol client is as follows:

  1. Create a Rails application for a Web service.
  2. Create a Web service.
  3. Define the API method or methods and implement the method in the controller class.
  4. Create a Rails application for the protocol client.
  5. Define the API class and the API method or methods.
  6. Access the Web service from the client application controller using the web_client_api option, an instance of the ActionWebService::Client::Soap, or ActionWebService::Client::XmlRpc.
  7. Implement the API methods in the client controller class.
  8. Start the Web service on port 3001.
  9. Start the client application on port 3000.
  10. Invoke the API methods from an RHTML view template and output the Web service output to another RHTML view template.

Conclusion

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.

Resources

Learn

Get products and technologies

Discuss

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into Open source on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Open source
ArticleID=349665
ArticleTitle=Create Web services with Ruby on Rails and Action Web Service
publish-date=11042008