Rack RESTful Dispatcher

Quoting the authors, Rack provides a minimal, modular and adaptable interface for developing web applications in Ruby. By wrapping HTTP requests and responses in the simplest way possible, it unifies and distills the API for web servers, web frameworks, and software in between (the so-called middleware) into a single method call.

To test the theory in practice, I put together a superficial interface for writing RESTful HTTP services by implementing any of the DELETE, GET, POST, PUT, etc HTTP verbs in Ruby classes.

require "rubygems"
require "rack"

module RestfulDispatcher
  def call(env)
    request = Rack::Request.new(env)
    dispatcher = dispatcher_class.new(request)
    body = dispatcher.send(request.request_method.downcase)
    [200, {'Content-Type' => dispatcher.content_type}, body]
  end

  def dispatcher_class
    @dispatcher ||= Class.new(self.class) do
      attr_accessor :content_type

      def initialize(request)
        @request, @content_type = request, 'text/xml'
      end
    end
  end

  module SingletonMethods
    def start(handler, host, port)
      handler.run Rack::Lint.new(self.new), :Host => host, :Port => port
    end
  end

  def self.included(receiver)
    receiver.extend SingletonMethods
  end
end

Let’s examine the example one method at a time.

All Rack applications must implement one method - call - which accepts one argument, the environment, which encapsulates data relevant to the HTTP roundtrip. The call method must return an array of 3 items: a greater than 100 integer representation of the response status, a hash holding name/value pairs representing the response’s header entries and an array of strings - the body of the response.

In the case of the RestfulDispatcher module, call first wraps env in Rack::Request, a convenient and stateless interface to the Rack environment. We then create a new instance of a dispatcher class passing it the Rack Request. We will revisit this in more detail when talking about the dispatcher_class method. Instantiating a new dispatcher to handle the request should keep things thread safe. We then call a method on the dispatcher instance corresponding to the HTTP verb included in the request. This call should return the response body. Finally, adhering to the Rack standard, we return an array containing the response status code, headers and body.

dispatcher_class creates a new class by subclassing the service we will be defining and giving it a constructor that accepts a request object. We also expose the content_type field, in case we want to override it anywhere in our service’s implementation.

Finally, we provide a start singleton method which we can call to start the service.

Mixing the RestfulDispatcher module in a class will effectively enable the class to act as a standalone RESTful service. All we need to do is implement instance methods that correspond to the HTTP verbs we want the service to respond to.

class FooService
  include RestfulDispatcher

  def get
    "<test>#{@request.GET['key']}</test>"
  end
end

require "thin"
FooService.start Rack::Handler::Thin, '127.0.0.1', 2323

Rack::Request#GET conveniently returns the data received in the request query string (e.g http://127.0.0.1/?key=hello) as a hash.

Thanks to Rack’s modular nature, switching from Thin to Mongrel is as easy as replacing the last two lines of the code above with:

require "mongrel"
FooService.start Rack::Handler::Mongrel, '127.0.0.1', 2323

7 Responses to “Rack RESTful Dispatcher”

  1. Frank Carver Says:

    This looks a lot like the a naive version of Mojasef Java framework which I have been using successfully for several years now.

    I’m surprised at the choice of an array of strings for the body type, though. I wonder how that is supposed to handle non-textual responses, such as serving an image, for example.

  2. George Malamidis Says:

    http://rack.rubyforge.org/doc/classes/Rack/File.html

  3. links for 2008-01-30 &laquo; Bloggitation Says:

    [...] Rack RESTful Dispatcher (tags: ruby rest web programming web2.0) [...]

  4. Web 2.0 Announcer Says:

    Rack RESTful Dispatcher…

    [...]Example of using Rack to create standalone RESTFul services in Ruby.[...]…

  5. links for 2008-01-30 | Lazycoder Says:

    [...] Nutrun » Blog Archive » Rack RESTful Dispatcher (tags: ruby rack programming) [...]

  6. lucasjosh.com &#187; Blog Archive &#187; Links for 1/30/08 [my NetNewsWire tabs] Says:

    [...] Nutrun » Blog Archive » Rack RESTful Dispatcher [...]

  7. Peter Cooper Says:

    Frank: It doesn’t really matter. Ruby just treats strings as series of 8 bit bytes, so you can store an image in a string, or whatever. Piping it out via HTTP via a string will work fine. For example, if you made it use image/gif for the content type, you could easily just send File.read(’whatever.gif’) straight back and it’d work.

Leave a Reply