Exposing Web Services on Your Web Site
Problem
You want to offer SOAP and XML-RPC web services from your web application.
Solution
Rails comes with a built-in web service generator that makes it easy to expose a controllers actions as web services. You don have to spend time writing WSDL files or even really know how SOAP and XML-RPC work.
Heres a simple example. First, follow the directions in Recipe 15.16 to create a database table named items, and to generate a model for that table. Don generate a controller.
Now, run this from the command line:
./script/generate web_service Item add edit fetch create app/apis/ exists app/controllers/ exists test/functional/ create app/apis/item_api.rb create app/controllers/item_controller.rb create test/functional/item_api_test.rb
This creates an item controller that supports three actions: add, edit, and fetch. But instead of web application actions with .rhtml views, these are web service actions that you access with SOAP or XML-RPC.
A Ruby method doesn care about the data types of the objects it accepts as arguments, or the data type of its return value. But a SOAP or XML-RPC web service method does care. To expose a Ruby method through a SOAP or XML-RPC interface, we need to define type information for its signature. Open up the file app/apis/item_api.rb and edit it to look like this:
class ItemApi < ActionWebService::API::Base api_method :add, :expects => [:string, :string], :returns => [:int] api_method :edit, :expects => [:int, :string, :string], :returns => [:bool] api_method :fetch, :expects => [:int], :returns => [Item] end
Now we need to implement the actual web service interface. Open app/controllers/item_controller.rb and edit it to look like this:
class ItemController < ApplicationController wsdl_service_name Item def add(name, value) Item.create(:name => name, :value => value).id end def edit(id, name, value) Item.find(id).update_attributes(:name => name, :value => value) end def fetch(id) Item.find(id) end end
Discussion
The item controller now implements SOAP and XML-RPC web services for the items table. This controller can live alongside an items controller that implements a traditional web interface.[8]
[8] You can even add your web interface actions to the ItemController class. Then a single controller will implement both the traditional web interface and the web service interface. But you can define a web application action with the same name as a web service action, because a controller class can contain only one method with a given name.
The URL to the XML-RPC API is http://www.yourserver.com/item/api, and the URL to the SOAP API is http://www.yourserver.com/item/service.wsdl. To test these services, heres a short Ruby script that calls the web service methods through a SOAP client:
require soap/wsdlDriver wsdl = "http://localhost:3000/item/service.wsdl" item_server = SOAP::WSDLDriverFactory.new(wsdl).create_rpc_driver item_id = item_server.add(foo, ar) if item_server.edit(item_id, John, Doe) puts Hey, it worked! else puts Back to the drawing board… end # Hey, it worked! item = item_server.fetch(item_id) item.class # => SOAP::Mapping::Object item.name # => "John" item.value # => "Doe"
Heres the XML-RPC equivalent:
require xmlrpc/client item_server = XMLRPC::Client.new2(http://localhost:3000/item/api) item_id = item_server.call(Add, foo, "bar") if item_server.call(Edit, item_id, John, Doe) puts Hey, it worked! else puts Back to the drawing board… end # Hey, it worked! item = item_server.call(Fetch, item_id) # => {"name"=>"John", "id"=>2, "value"=>"Doe"} item.class # => Hash
See Also
- Matt Biddulphs article "REST on Rails" describes how to create REST-style web services on top of Rails (http://www.xml.com/pub/a/2005/11/02/rest-on-rails.html)
- Recipe 16.3, "Writing an XML-RPC Client," and Recipe 16.4, "Writing a SOAP Client"
- Recipe 16.5, "Writing a SOAP Server," shows a nonRails implementation of SOAP web services
Категории