Patchbay

Patchbay is a minimal web framework designed to let you add HTTP APIs to existing Ruby-based applications with minimum effort and frustration:

# test.rb
require 'patchbay'
require 'json'

class MyInterface < Patchbay
  attr_accessor :rest_of_app

  get '/' do
    render :json => rest_of_app.some_data_structure.to_json
  end
end

class RestOfApp
    def some_data_structure
        { 'a' => 'b', 'c' => 'd' }
    end
end

rest_of_app = RestOfApp.new
interface = MyInterface.new

interface.rest_of_app = rest_of_app
interface.run(:Host => '::', :Port => 3000)

Basics

A Patchbay interface is a class derived from the Patchbay class. Routes are defined in the interface using the `get`, `put`, `post`, and `delete` class methods. Each of these takes a block that is invoked when an incoming request matches the route.

Routes can contain symbols representing variable parameters:

get '/say/:something' { render :html => params[:something] }

The parameters are accessed via the “params” instance method, which returns a hash of all parameters interpolated from the URL. Query strings are not supported (yet).

To start serving up the API, instantiate your interface then call its “run” method. This can be from a separate thread of control, and probably should be if your application is doing other tasks in the background.

Rendering

The render instance method sets the response content. For example,

render :html => '<html><body>Hello World</body></html>'

sends the greeting to the browser with a content type of 'text/html'. Content types are guessed intelligently using Rack::Mime, so things like

render :json => '{ :a => "b" }'

and

render :jpg => some_jpeg_data

should be supported.

The render method supports setting the response status code:

render :error => 404, :html => your_404_page

Files can be sent instead of rendering some string content:

send_file '/path/to/file'

Note that no protection is provided against directory-traversal when using send_file. The files_dir facility should be used for serving static files.

Static Files

To serve up static files alongside your interface, set the `files_dir` attribute on your interface class:

class MyInterface
    self.files_dir = "/path/to/static/files"
    ... routes and handlers ...
end

The path may be either absolute or relative. If no route is matched by an incoming request, Patchbay will try to find a matching file in the path given. Requested filenames are canonicalized using File.realpath and checked that they fall within the path provided. This prevents directory-traversal attacks, but also will result in errors if symlinks within the static files path point to an outside location.

Interface Instances

Interface instances can have attributes and instance variables, like instances of any other Ruby class. This enables a Patchbay interface to be connected to any application objects with minimum effort. The attributes, instance variables, and instance methods are accessible to the request handlers.

An interface instance is a valid Rack application, so Patchbay works with servers including WEBrick, Mongrel, and Thin. There is an example Rack configuration in the examples directory.

License

Copyright (C) 2011 by Andrew H. Armenia.

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.