ActionWebService is back

Posted on July 02, 2008

I've been porting several of my old applications to the latest version of Rails. It turned out not that a difficult thing to do. But unfortunately some of them rely on ActionWebService gem that appears to be left behind of the latest Rails development. Because of the lack of time, I stepped away from being a maintainer of this library some time ago and it seems that no one has taken this position. Not surprisingly, building REST API is so much easier and kosher nowadays.

For those of you who still need to provide SOAP/XML-RPC API, I've uploaded my port of ActionWebService to GitHub. Note that it depends on Rails version 2.1.0.

This is how you install it:

$ sudo gem install datanoise-actionwebservice --source http://gems.github.com

Below is a small refresher of how to use this thing:

Configuration

Assuming that you installed the gem:

  1. Add this line to your config/environment.rb file in the initializer section:

    config.gem 'datanoise-actionwebservice', :lib => 'actionwebservice'
    
  2. Add this require statement to test/test_helper.rb file:

    require 'action_web_service/test_invoke'
    

Generating API controller

ActionWebService gem includes web_service generator that you can use like this:

$ ./script/generate web_service post
      exists  app/services/
      exists  app/controllers/
      exists  test/functional/
      create  app/services/post_api.rb
      create  app/controllers/post_controller.rb
      create  test/functional/post_api_test.rb

Note that your Apis are placed into app/services directory which Rails automatically includes in the search path, instead of the old app/apis directory.

Define your API

Open app/services/post_api.rb file and add methods that your service exposes:

class PostApi < ActionWebService::API::Base
  api_method :get_posts, :returns => [[:string]]
end

Here, we defined get_posts method that accepts no parameters and returns an array of strings.

API implementation

We are going to use direct dispatching mode, so all methods that implement our API go directly to PostController itself:

class PostController < ApplicationController
  wsdl_service_name 'Post'
  web_service_api PostApi
  web_service_scaffold :invocation if Rails.env == 'development'

  def get_posts
    ["Post 1", "Post 2"]
  end
end

Several things need to mention here:

  1. We use scaffolding in the development mode, so we can easily test our API via the browser. Just go to http://localhost:3000/post/invocation and follow the screens to make an API call.

  2. You can get WSDL of our Post API from http://localhost:3000/post/wsdl:

    $ curl http://localhost:3000/post/wsdl
    <?xml version="1.0" encoding="UTF-8"?>
    <definitions name="Post" xmlns:typens="urn:ActionWebService"> ...
    
  3. The URL that you actually use to make API calls is http://localhost:3000/post/api

Unit Testing

As you probably noticed, our web_service generator created a unit test file test/functional/post_api_test.rb. Lets test our get_posts method:

require File.dirname(__FILE__) + '/../test_helper'
require 'post_controller'

class PostController; def rescue_action(e) raise e end; end

class PostControllerApiTest < Test::Unit::TestCase
  def setup
    @controller = PostController.new
    @request    = ActionController::TestRequest.new
    @response   = ActionController::TestResponse.new
  end

  def test_get_posts
    result = invoke :get_posts
    assert_equal(["Post 1", "Post 2"], result)
  end
end

Lets see if it works:

$ ruby test/functional/post_api_test.rb 
Loaded suite test/functional/post_api_test
Started
.
Finished in 0.182469 seconds.

1 tests, 1 assertions, 0 failures, 0 errors

OK, we are good to go!

Comments
  1. ZackJuly 02, 2008 @ 07:21 PM

    What changes if any were made in the port? I run AWS with Rails 2.1 fine in a few of may apps. Glad to see the code on github :)

  2. KentJuly 03, 2008 @ 01:57 AM

    Zack,

    I made numerous changes, but most important ones are:

    1. Fixed casting of :time type parameters.

    2. Renamed template files according to new .html.erb naming schema.

    3. Made all unit tests pass again.

    4. Recovered generator classes from rails-1.2.6 gem

    Basically, I just wanted to have an easy way to install this library for my old applications. :)

  3. ZackJuly 03, 2008 @ 10:56 AM

    Great!

    Glad to hear that a maintainable branch is up and easy to fork... because unfortunately this is a much needed library for many of my apps too...

  4. Steve RawlinsonJuly 09, 2008 @ 12:24 PM

    Thanks very much for this, I was struggling to get AWS working with 2.1.

    Your instructions worked fine but in case anyone else hits the same problem as I did - namely a cryptic error loading the environment, you might need to run gem update --system if you have not used 'config.gem' before. More details of the problem are here:

    http://rails.lighthouseapp.com/projects/8994/tickets/462-loading-environment-fails-with-an-outdated-version-of-rubygems-while-using-config-gem-some_gem

  5. Steve RawlinsonJuly 09, 2008 @ 01:39 PM

    I ought to mention I also had to cp actionwebservice.rb datanoise-actionwebservice.rb in lib/ before config.gem would find the gem.

    steve

  6. Larry EdelsetinJuly 13, 2008 @ 07:13 PM

    Steve was dead right on both those counts. Please update that package with the copied file...I'm not git-enabled yet myself.

  7. KentJuly 14, 2008 @ 01:16 PM

    The solution is to add :lib => 'actionwebservice' to the config.gem

  8. Hermann KurzJuly 16, 2008 @ 09:31 AM

    Hi, if i try to access a datetime column of an activerecord object (ie createdat or modifiedat) , i get the following error. The error does not appear, if the column contains NULL. Anybody knows a a workaround or fix for this problem?

    SOAP::Mapping::MappingError (Cannot map Array to SOAP/OM.):
    /Applications/NetBeans/NetBeans 6.1.app/Contents/Resources/NetBeans/ruby2/jruby-1.1/lib/ruby/1.8/soap/mapping/registry.rb:468:in `_obj2soap'
    /Applications/NetBeans/NetBeans 6.1.app/Contents/Resources/NetBeans/ruby2/jruby-1.1/lib/ruby/1.8/soap/mapping/registry.rb:420:in `obj2soap'
    /Applications/NetBeans/NetBeans 6.1.app/Contents/Resources/NetBeans/ruby2/jruby-1.1/lib/ruby/1.8/soap/mapping/mapping.rb:127:in `_obj2soap'
    /Applications/NetBeans/NetBeans 6.1.app/Contents/Resources/NetBeans/ruby2/jruby-1.1/lib/ruby/1.8/soap/mapping/mapping.rb:47:in `obj2soap'
    /Applications/NetBeans/NetBeans 6.1.app/Contents/Resources/NetBeans/ruby2/jruby-1.1/lib/ruby/1.8/soap/mapping/mapping.rb:360:in `protect_threadvars'
    /Applications/NetBeans/NetBeans 6.1.app/Contents/Resources/NetBeans/ruby2/jruby-1.1/lib/ruby/1.8/soap/mapping/mapping.rb:43:in `obj2soap'
    /vendor/gems/datanoise-actionwebservice-2.1.0/lib/action_web_service/protocol/soap_protocol/marshaler.rb:42:in `ruby_to_soap'
    /vendor/gems/datanoise-actionwebservice-2.1.0/lib/action_web_service/protocol/soap_protocol.rb:114:in `encode_response'
    /vendor/gems/datanoise-actionwebservice-2.1.0/lib/action_web_service/dispatcher/abstract.rb:192:in `web_service_create_response'
    /vendor/gems/datanoise-actionwebservice-2.1.0/lib/action_web_service/dispatcher/abstract.rb:62:in `web_service_invoke'
        /vendor/gems/datanoise-actionwebservice-2.1.0/lib/action_web_service/dispatcher/abstract.rb:25:in `invoke_web_service_request'
    
  9. knmeJuly 25, 2008 @ 02:28 PM

    I am having a similar problem. I believe it happened after we upgraded to rails v2.1.

    Any help would be greatly appreciated.

  10. knmeJuly 28, 2008 @ 03:59 PM

    We're leaning towards the changes to the date object in Rails v2.1.

  11. Geoff BallingerJuly 31, 2008 @ 04:57 AM

    Appears that there is a problem with running AWS against JRuby which is a pity ...

    http://jira.codehaus.org/browse/JRUBY-2446

    I certainly run into this error when using JRuby 1.1.2, Rails 2.1.0, and datanoise-actionwebservice.

    Geoff.

  12. Steve RawlinsonAugust 07, 2008 @ 10:58 AM

    For some reason Exeption Notifier does not send me emails if an exception occurs in code being called from the AWS XML-RPC interface. Does anyone know how to get that working with AWS?

Post a comment
Comment





You may use Markdown in your comments, so please give your code snippets a four-space indent.