README
364 lines
| 9.9 KiB
| text/plain
|
TextLexer
|
r962 | = Action Web Service -- Serving APIs on rails | ||
Action Web Service provides a way to publish interoperable web service APIs with | ||||
Rails without spending a lot of time delving into protocol details. | ||||
== Features | ||||
* SOAP RPC protocol support | ||||
* Dynamic WSDL generation for APIs | ||||
* XML-RPC protocol support | ||||
* Clients that use the same API definitions as the server for | ||||
easy interoperability with other Action Web Service based applications | ||||
* Type signature hints to improve interoperability with static languages | ||||
* Active Record model class support in signatures | ||||
== Defining your APIs | ||||
You specify the methods you want to make available as API methods in an | ||||
ActionWebService::API::Base derivative, and then specify this API | ||||
definition class wherever you want to use that API. | ||||
The implementation of the methods is done separately from the API | ||||
specification. | ||||
==== Method name inflection | ||||
Action Web Service will camelcase the method names according to Rails Inflector | ||||
rules for the API visible to public callers. What this means, for example, | ||||
is that the method names in generated WSDL will be camelcased, and callers will | ||||
have to supply the camelcased name in their requests for the request to | ||||
succeed. | ||||
If you do not desire this behaviour, you can turn it off with the | ||||
ActionWebService::API::Base +inflect_names+ option. | ||||
==== Inflection examples | ||||
:add => Add | ||||
:find_all => FindAll | ||||
==== Disabling inflection | ||||
class PersonAPI < ActionWebService::API::Base | ||||
inflect_names false | ||||
end | ||||
==== API definition example | ||||
class PersonAPI < ActionWebService::API::Base | ||||
api_method :add, :expects => [:string, :string, :bool], :returns => [:int] | ||||
api_method :remove, :expects => [:int], :returns => [:bool] | ||||
end | ||||
==== API usage example | ||||
class PersonController < ActionController::Base | ||||
web_service_api PersonAPI | ||||
def add | ||||
end | ||||
def remove | ||||
end | ||||
end | ||||
== Publishing your APIs | ||||
Action Web Service uses Action Pack to process protocol requests. There are two | ||||
modes of dispatching protocol requests, _Direct_, and _Delegated_. | ||||
=== Direct dispatching | ||||
This is the default mode. In this mode, public controller instance methods | ||||
implement the API methods, and parameters are passed through to the methods in | ||||
accordance with the API specification. | ||||
The return value of the method is sent back as the return value to the | ||||
caller. | ||||
In this mode, a special <tt>api</tt> action is generated in the target | ||||
controller to unwrap the protocol request, forward it on to the relevant method | ||||
and send back the wrapped return value. <em>This action must not be | ||||
overridden.</em> | ||||
==== Direct dispatching example | ||||
class PersonController < ApplicationController | ||||
web_service_api PersonAPI | ||||
def add | ||||
end | ||||
def remove | ||||
end | ||||
end | ||||
class PersonAPI < ActionWebService::API::Base | ||||
... | ||||
end | ||||
For this example, protocol requests for +Add+ and +Remove+ methods sent to | ||||
<tt>/person/api</tt> will be routed to the controller methods +add+ and +remove+. | ||||
=== Delegated dispatching | ||||
This mode can be turned on by setting the +web_service_dispatching_mode+ option | ||||
in a controller to <tt>:delegated</tt>. | ||||
In this mode, the controller contains one or more web service objects (objects | ||||
that implement an ActionWebService::API::Base definition). These web service | ||||
objects are each mapped onto one controller action only. | ||||
==== Delegated dispatching example | ||||
class ApiController < ApplicationController | ||||
web_service_dispatching_mode :delegated | ||||
web_service :person, PersonService.new | ||||
end | ||||
class PersonService < ActionWebService::Base | ||||
web_service_api PersonAPI | ||||
def add | ||||
end | ||||
def remove | ||||
end | ||||
end | ||||
class PersonAPI < ActionWebService::API::Base | ||||
... | ||||
end | ||||
For this example, all protocol requests for +PersonService+ are | ||||
sent to the <tt>/api/person</tt> action. | ||||
The <tt>/api/person</tt> action is generated when the +web_service+ | ||||
method is called. <em>This action must not be overridden.</em> | ||||
Other controller actions (actions that aren't the target of a +web_service+ call) | ||||
are ignored for ActionWebService purposes, and can do normal action tasks. | ||||
=== Layered dispatching | ||||
This mode can be turned on by setting the +web_service_dispatching_mode+ option | ||||
in a controller to <tt>:layered</tt>. | ||||
This mode is similar to _delegated_ mode, in that multiple web service objects | ||||
can be attached to one controller, however, all protocol requests are sent to a | ||||
single endpoint. | ||||
Use this mode when you want to share code between XML-RPC and SOAP clients, | ||||
for APIs where the XML-RPC method names have prefixes. An example of such | ||||
a method name would be <tt>blogger.newPost</tt>. | ||||
==== Layered dispatching example | ||||
class ApiController < ApplicationController | ||||
web_service_dispatching_mode :layered | ||||
web_service :mt, MovableTypeService.new | ||||
web_service :blogger, BloggerService.new | ||||
web_service :metaWeblog, MetaWeblogService.new | ||||
end | ||||
class MovableTypeService < ActionWebService::Base | ||||
... | ||||
end | ||||
class BloggerService < ActionWebService::Base | ||||
... | ||||
end | ||||
class MetaWeblogService < ActionWebService::API::Base | ||||
... | ||||
end | ||||
For this example, an XML-RPC call for a method with a name like | ||||
<tt>mt.getCategories</tt> will be sent to the <tt>getCategories</tt> | ||||
method on the <tt>:mt</tt> service. | ||||
== Customizing WSDL generation | ||||
You can customize the names used for the SOAP bindings in the generated | ||||
WSDL by using the wsdl_service_name option in a controller: | ||||
class WsController < ApplicationController | ||||
wsdl_service_name 'MyApp' | ||||
end | ||||
You can also customize the namespace used in the generated WSDL for | ||||
custom types and message definition types: | ||||
class WsController < ApplicationController | ||||
wsdl_namespace 'http://my.company.com/app/wsapi' | ||||
end | ||||
The default namespace used is 'urn:ActionWebService', if you don't supply | ||||
one. | ||||
== ActionWebService and UTF-8 | ||||
If you're going to be sending back strings containing non-ASCII UTF-8 | ||||
characters using the <tt>:string</tt> data type, you need to make sure that | ||||
Ruby is using UTF-8 as the default encoding for its strings. | ||||
The default in Ruby is to use US-ASCII encoding for strings, which causes a string | ||||
validation check in the Ruby SOAP library to fail and your string to be sent | ||||
back as a Base-64 value, which may confuse clients that expected strings | ||||
because of the WSDL. | ||||
Two ways of setting the default string encoding are: | ||||
* Start Ruby using the <tt>-Ku</tt> command-line option to the Ruby executable | ||||
* Set the <tt>$KCODE</tt> flag in <tt>config/environment.rb</tt> to the | ||||
string <tt>'UTF8'</tt> | ||||
== Testing your APIs | ||||
=== Functional testing | ||||
You can perform testing of your APIs by creating a functional test for the | ||||
controller dispatching the API, and calling #invoke in the test case to | ||||
perform the invocation. | ||||
Example: | ||||
class PersonApiControllerTest < Test::Unit::TestCase | ||||
def setup | ||||
@controller = PersonController.new | ||||
@request = ActionController::TestRequest.new | ||||
@response = ActionController::TestResponse.new | ||||
end | ||||
def test_add | ||||
result = invoke :remove, 1 | ||||
assert_equal true, result | ||||
end | ||||
end | ||||
This example invokes the API method <tt>test</tt>, defined on | ||||
the PersonController, and returns the result. | ||||
=== Scaffolding | ||||
You can also test your APIs with a web browser by attaching scaffolding | ||||
to the controller. | ||||
Example: | ||||
class PersonController | ||||
web_service_scaffold :invocation | ||||
end | ||||
This creates an action named <tt>invocation</tt> on the PersonController. | ||||
Navigating to this action lets you select the method to invoke, supply the parameters, | ||||
and view the result of the invocation. | ||||
== Using the client support | ||||
Action Web Service includes client classes that can use the same API | ||||
definition as the server. The advantage of this approach is that your client | ||||
will have the same support for Active Record and structured types as the | ||||
server, and can just use them directly, and rely on the marshaling to Do The | ||||
Right Thing. | ||||
*Note*: The client support is intended for communication between Ruby on Rails | ||||
applications that both use Action Web Service. It may work with other servers, but | ||||
that is not its intended use, and interoperability can't be guaranteed, especially | ||||
not for .NET web services. | ||||
Web services protocol specifications are complex, and Action Web Service client | ||||
support can only be guaranteed to work with a subset. | ||||
==== Factory created client example | ||||
class BlogManagerController < ApplicationController | ||||
web_client_api :blogger, :xmlrpc, 'http://url/to/blog/api/RPC2', :handler_name => 'blogger' | ||||
end | ||||
class SearchingController < ApplicationController | ||||
web_client_api :google, :soap, 'http://url/to/blog/api/beta', :service_name => 'GoogleSearch' | ||||
end | ||||
See ActionWebService::API::ActionController::ClassMethods for more details. | ||||
==== Manually created client example | ||||
class PersonAPI < ActionWebService::API::Base | ||||
api_method :find_all, :returns => [[Person]] | ||||
end | ||||
soap_client = ActionWebService::Client::Soap.new(PersonAPI, "http://...") | ||||
persons = soap_client.find_all | ||||
class BloggerAPI < ActionWebService::API::Base | ||||
inflect_names false | ||||
api_method :getRecentPosts, :returns => [[Blog::Post]] | ||||
end | ||||
blog = ActionWebService::Client::XmlRpc.new(BloggerAPI, "http://.../xmlrpc", :handler_name => "blogger") | ||||
posts = blog.getRecentPosts | ||||
See ActionWebService::Client::Soap and ActionWebService::Client::XmlRpc for more details. | ||||
== Dependencies | ||||
Action Web Service requires that the Action Pack and Active Record are either | ||||
available to be required immediately or are accessible as GEMs. | ||||
It also requires a version of Ruby that includes SOAP support in the standard | ||||
library. At least version 1.8.2 final (2004-12-25) of Ruby is recommended; this | ||||
is the version tested against. | ||||
== Download | ||||
The latest Action Web Service version can be downloaded from | ||||
http://rubyforge.org/projects/actionservice | ||||
== Installation | ||||
You can install Action Web Service with the following command. | ||||
% [sudo] ruby setup.rb | ||||
== License | ||||
Action Web Service is released under the MIT license. | ||||
== Support | ||||
The Ruby on Rails mailing list | ||||
Or, to contact the author, send mail to bitserf@gmail.com | ||||