Using ActiveResource to consume web-services
Today I’m reviewing Joe Van Dyk’s monkeycharger application, which is a web-service for storing and charging credit cards. I loved looking at this app, because its only interface is a RESTful web service: there is no HTML involved. (If you’ve never written an app that only exposes a web-service UI, you ought to. It’s a blast.)
In general, Joe has done a fantastic job with keeping the controllers slim and moving logic to models. The only significant gripe I had with the application is that it is not ActiveResource compatible.
For those of you that are late to the party, ActiveResource is the newest addition to the Rails family. It lets you declare and consume web-services using an ActiveRecord-like interface…BUT. It is opinionated software, just like the rest of Rails, and makes certain assumptions about the web-services being consumed.
- The service must understand Rails-style REST URLs. (e.g. “POST /credit_cards.xml” to create a credit card, etc.)
- The service must respond with a single XML-serialized object (Rails-style).
- The service must make appropriate use of HTTP status codes (404 if the requested record cannot be found, 422 if any validations fail, etc.).
It’s really not much to ask, and working with ActiveResource (or “ares” as we affectively call it) is a real joy.
However, monkeycharger tends to do things like the following:
1 2 3 4 5 6 7 8 9 10 |
class AuthorizationsController < ApplicationController def create @credit_card = Authorizer.prepare_credit_card_for_authorization(params) transaction_id = Authorizer::authorize!(:amount => params[:amount], :credit_card => @credit_card) response.headers['X-AuthorizationSuccess'] = true render :text => transaction_id rescue AuthorizationError => e render :text => e.message end end |
Three things: the request is not representing an “authorization” object, the response is not XML, and errors are not employing HTTP status codes to indicate failure.
Fortunately, this is all really, really easy to fix. First, you need (for this specific example) an Authorization model (to encapsulate both the the XML serialization and the actual authorization).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
class Authorization attr_reader :attributes def initialize(attributes) @attributes = attributes end def credit_card @credit_card ||= Authorizer.prepare_credit_card_for_authorization(attributes) end def authorize! @transaction_id = Authorizer.authorize!(:amount => attributes[:amount], :credit_card => credit_card) end def to_xml { :transaction_id => @transaction_id }.to_xml(:root => "authorization") end end |
Then, we rework the AuthorizationsController to use the model:
1 2 3 4 5 6 7 8 |
class AuthorizationsController < ApplicationController def create authorization = Authorization.new(params[:authorization]) authorization.authorize! render :xml => authorization.to_xml, :status => :created rescue AuthorizationError => e render :xml => "<errors><error>#{e.message}</error></errors>", :status => :unprocessable_entity end |
(Note the use of the “created” status, which is HTTP status code 201. Other verbs just use “ok”, status code 200, to indicate success. Also, with an error, we return an “unprocessable_entity” status, which is HTTP status code 422. ActiveResource will treat that as a failed validation.)
With that change, you could now use ActiveResource to authorize a credit card transaction:
1 2 3 4 5 6 7 8 9 10 11 12 |
class Authorization < ActiveResource::Base self.site = "http://my.monkeycharger.site" end auth = Authorization.new(:amount => 15, :credit_card_id => 1234, :remote_key => remote_key_for_card) if auth.save puts "success: #{auth.transaction_id}" else puts "error: #{auth.errors.full_messages.to_sentence}" end |
It should be mentioned, too, that making an app ActiveResource-compatible does nothing to harm compatibility with non-ActiveResource clients. Everything is XML, both ways, with HTTP status codes being used to report whether a request succeeded or not. Win-win!
Obviously, real, working code trumps theoretical whiteboard sketches every time, and Joe is to be congratulated on what’s done. Even though ActiveResource-compatibility can buy you a lot, you should always evaluate whether you really need it and implement accordingly.
SignOut: Part 2
Here we go, continuing the RESTful refactoring of Randy Schmidt’s “SignOut” application. In Part 1 I talked at a high level about how the existing application could be viewed as an interface to several different resources. In this article, I’ll show you how to implement the “employees” resource. I’ll be doing this by just showing you heavily commented code snippets.
Note that, for this article, I am not using the SimplyHelpful plugin. This is mostly so that I can demonstrate how this all would work with current Rails, without all the convenience magic that SimplyHelpful adds in. Once you understand how this all fits together, though, SimplyHelpful is an enormous time saver.
Firstly, we define the routes we need:
1 2 3 4 5 6 7 8 9 |
ActionController::Routing::Routes.draw do |map| # So far, our RESTful implementation has only a single resource defined, # employees. We use map.resources to set up all the routes (named and # otherwise) that we will need. This assumes the existence of a controller # named EmployeesController. map.resources :employees end |
Then, we implement our controller:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
# This replaces the AdminController in the original implementation. It # provides an interface to the employees resource, allowing employees to be # listed, edited, created, and destroyed. # # Note a few things about this implementation: # # * I'm using respond_to in a few of the actions, to demonstrate how trivial # it is to make your application into a web-service. There's really very # little reason _not_ to do it. # # * I'm not bothering with any kind of authorization mechanism, because the # original wasn't either. However, in practice, I'd be using HTTP # authentication in a before_filter to make sure only people authorized # as administrators were accessing this resource. # # * Note the extensive use of named routes; map.resources sets up a bunch for # you, for free, and they work WONDERS in cleaning up both your controllers # and your views. class EmployeesController < ApplicationController # Rather than doing Employee.find(params[:id]) in all the actions that need # to, just use a before filter. This makes it obvious which actions need # an employee ID, and keeps things DRY. before_filter :find_employee, :only => %w(show update destroy) # Return a list of all employees currently in the system. def index @employees = Employee.find(:all) respond_to do |format| # If we don't give a block, the default behavior is used, which (for # HTML) is to render the "employees/index.rhtml" template. format.html # We specify the :root option here, because if the list of employees # is empty, you'd otherwise get tags like <NilClass>. format.xml { render :xml => @employees.to_xml(:root => "employees") } end end # We could technically leave this action out completely, since Rails will # find the new.rhtml template and render it just fine, but it's nice to be # able to tell by looking at the controller what actions are defined. def new end # Creates a new employee. It expects a hash to come in with a single # :employee key, which points to a subhash of the attributes to use to # create the employee. def create @employee = Employee.create(params[:employee]) respond_to do |format| # If we're in HTML mode, redirect back to the master list. format.html { redirect_to(employees_path) } # If we're in XML mode, just return a 201 Created response. format.xml { head :created, :location => employee_path(@employee) } end end # Display the requested employee record. For this app, we just use this # to display the form for modifying the employee. def show respond_to do |format| format.html format.xml { render :xml => @employee.to_xml } end end # Update the specified employee record. Expects the same input format as # the #create action. def update @employee.update_attributes(params[:employee]) respond_to do |format| format.html { redirect_to(employee_path(@employee)) } # "head" is a wildly useful little method. It just returns a blank # HTTP response, which is often what you want when dealing with XML # requests. Here, we just say to return a "200 OK" response with no # body. format.xml { head :ok } end end # Destroy the specified employee record. def destroy @employee.destroy respond_to do |format| format.html { redirect_to(employees_path) } format.xml { head :ok } end end private def find_employee @employee = Employee.find(params[:id]) end end |
And, lastly, we implement our RHTML views:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
<!-- employees/index.rhtml Pretty much the same as the original, but this one makes use of the named routes provided by map.resources. Also note that for the "Delete" link, you have to set the :method to :delete, since RESTful actions use the same URL with different HTTP verbs to differentiate the actions. --> <p><%= link_to "Add", new_employee_path, :class => "Add" %></p> <ul> <% @employees.each do |employee| %> <li> <%= employee.last_first %> <%= link_to "Edit", employee_path(employee), :class => "Edit" %> <%= link_to "Delete", employee_path(employee), :method => :delete, :confirm => "Are you sure you want to delete #{employee.name}?", :class => "Delete" %> </li> <% end %> </ul> <!-- employees/new.rhtml We set up the form to POST to the /employees resource, which will create the new record. Note the use of form_for, which yields an instance of FormBuilder. This lets us do things like "f.text_field(:firstname)" and have the text field set up with the correct name ("employee[firstname]"). This makes it dead simple to get the kind of nested hashes that RESTful actions expect (see #create and #update). --> <% form_for :employee, Employee.new, :url => employees_path do |f| %> <%= render :partial => "employees/form", :locals => { :form => f } %> <% end %> <!-- employees/show.rhtml Pretty much the same as new.rhtml, but this time we post to the URI for a specific employee. We also set the HTTP verb to PUT, via the _method parameter. --> <% form_for :employee, @employee, :url => employee_path(@employee) do |f| %> <%= hidden_field :_method, :put %> <%= render :partial => "employees/form", :locals => { :form => f } %> <% end %> <!-- employees/_form.rhtml This expects a local variable 'form' to exist, which points to a FormBuilder instance. --> <dl> <dt><label for="employee_firstname">First Name:</label></dt> <dd><%= form.text_field :firstname, :size => '30', :maxlength => '100' %></dd> <dt><label for="employee_initials">Initials:</label></dt> <dd><%= form.text_field :initials, :size => '5', :maxlength => '5' %></dd> <!-- etc, etc, etc. --> </dl> |
And that’s the first resource! In the next article, I’ll illustrate the StatusesController.
SignOut: Part 1
Randy Schmidt sent us a project of his called SignOut, which he wrote for work and which “lets people sign in and out for meetings/lunch from their browser.” It’s a pretty simple application; an administrator first uses the admin interface to add the employees to the system, and employees can then go in and mark themselves as “away” or “not away”. (The repository is here, and we’ll be reviewing revision 47…which I can’t link to directly, unfortunately.)
As it stands, there are only a few things about the application that make me cringe; for the most part I have no complaint with how it was architected. So instead of pointing out the little nitpicks, I thought this might be a prime opportunity to demonstrate the thinking processes that go into taking an existing non-RESTful application, and redesigning it as a RESTful app.
What is REST?
REST is a term that is getting a lot of traffic these days. At the risk of grossly oversimplifying, it basically refers to a way of writing your app such that the underlying resources are exposed via a consistent, URL-based interface formed from the basic HTTP operations of “get”, “post”, “put”, and “delete”. (I have absolutely no doubt that some will take issue with this definition; please feel free to expound on your own view of the technique by commenting below.)
Sound like a lot of work? It’s not, really, especially if you do it RESTfully from the get-go, instead of reworking an existing application after the fact. But even if it is easy, why should you bother? That’s a valid question, and one worth addressing before going into this any further.
Why REST?
First of all, a RESTful application will generally have more controllers, but each controller will be smaller. Smaller objects are happy objects. Smaller objects are easier to maintain. Smaller objects are easier to refactor. Smaller objects are, quite frankly, better than bigger objects.
Secondly, a RESTful application in Rails is guided by convention, which means all RESTful Rails apps will share some basic things, like the format of their URLs. This means that we can now write a framework for consuming RESTful web services, and have that framework easily communicate with any application that conforms to those Rails conventions. And guess what? That framework already exists, and is called ActiveResource.
Thirdly (and I openly acknowledge that this is largely a matter of opinion), RESTful apps look a lot cleaner on the inside. Each line of code is nicely groomed and placed on it’s shelf. Order prevails. Chaos quails.
Convinced yet? Alrighty then. Let’s move on.
Identifying Resources
So, when writing a RESTful app, the first step is to identify the resources that you want to expose, and then create at least one controller for each of those resources. It is tempting to think of your models as this set of resources, but that’s not actually correct. In the SignOut application, there is only one model: Employee. But by looking at the actions of the two existing controllers, I was able to extract three different resources.
As the application is written, here’s the list of all of its actions:
AdminController- #index: show all employees
- #add: creates a new employee record
- #edit: displays the employee edit form (if called via GET) or updates a specific employee (if called via POST)
- #delete: deletes an existing employee
- #set_view: just sets a :view key in the session, which determines whether the status view should be brief or verbose.
- #status: shows a list of all employees in the system, along with their status. From this view, employees may mark themselves as “away”, or “available”.
- #periodic and EmployeeController#search: returns all employees matching the given criteria. These are pretty much the same operation, with the difference that #periodic is called every 10 seconds (so the view remains up-to-date).
- #set_away_info: returns the HTML form (via AJAX) that employees may use to make themselves as “away”. It allows things like the reason to be specified, along with the state.
- #set_away: updates the Employee record with the information specified by the #set_away_info form.
- #come_back: clears the away status information from the Employee’s record.
First off, note that the AdminController is the part that actually controls the employees, creating, reading, updating, and deleting them. Thus, in my refactoring, the AdminController gets renamed to EmployeesController (note the plural; controllers in a RESTful Rails app are named for the plural of the resource they control).
Second, note that the EmployeeController in the original version doesn’t really control the employees, it controls the employees’ statuses. So, I add a StatusesController. Lastly, note the EmployeeController#set_view action. This manipulates neither the employee, nor an employee’s status. It changes the view of an employee’s status, which suggests a third resource: views, which will be managed by a ViewsController.
Status is a fairly generic name for the messages about a person’s status. Judging by the application the only thing these are used for is a message indicating why someone’s away. Why not call them AwayMessages?
Also, instead of relying on a value in the session, you could move the choice of minimal/full into the URL, making your application more stateless, and remove the need for an entire controller.
So in my refactoring the three controllers and their actions are:
EmployeesController- #index: show all employees
- #new: display the “new employee” form
- #create: create a new employee
- #show: display the “edit” form for a specific employee
- #update: save an existing employee’s data
- #destroy: delete an existing employee
- #index: show the statuses of all employees. Specify a query parameter of :q for searches that filter this view.
- #show: show the away-info form for a specific employee
- #update: mark an employee as away
- #destroy: mark an employee as having come back from being away (“destroy” the away status)
- #show: sets the requested view in the session, and redirects back to StatusesController#index.
I’ll go through and implement these in subsequent articles, but don’t let that discourage you! Go ahead and think about how you would reimplement some of these yourself. Perhaps you’d even break the existing application into different resources than I did; feel free to try it out and see how it works.

