# # Gisted by harri.kauhanen ('AT') gmail.com # # Coucher - Super simple RESTful HTTP service with Rack and CouchFoo # Should work easily with ActiveRecord or other persistence frameworks. # This demo only supports HTTP GET requests on existing resources. # With tiny modifications it could support JSON output or Etag caching. # # Feel free to use and modify, but let me know your ideas as well, thanks! # # # To run it, you could e.g. 'rackup coucher.ru -p 3000' or attach to any Rack-capable server. # Or you could easily make it a Rails Metal and run along with the Rails stuff. # # # File: coucher.ru # # require 'rubygems' # require 'rack' # # require 'coucher.rb' # run Coucher.new # # # To consume the service, you could use HTTP GET to e.g. these resources: # # http://localhost:3000/people/ # http://localhost:3000/people/52a4e65a6735a65e899a120ef2e6a572 # http://localhost:3000/people/52a4e65a6735a65e899a120ef2e6a572/dogs # http://localhost:3000/people?name=Harri # http://localhost:3000/dogs/1793f7d6647b72d4f00c029c1b1649b5/person # require 'rubygems' require 'couch_foo' class Person < CouchFoo::Base property :name, String has_many :dogs end class Dog < CouchFoo::Base property :name, String property :person_id, String belongs_to :person end # # Define more models here. Note! No need to define "routes" or anything, HTTP interface just works. # class Coucher def initialize CouchFoo::Base.set_database(:database => 'people_and_dogs', :host => "localhost:5984") end def call(env) if env['REQUEST_METHOD'] != 'GET' return fail(400, 'This demo supports only GET requests') end slash, classname, id, nesting, other = env['PATH_INFO'].split('/') if other || classname.nil? return fail(400, 'Invalid path') end begin clazz = Kernel.const_get(classname.classify) if id if nesting res = clazz.find(id).send(nesting) if res.nil? return [200, {"Content-Type" => "text/xml"}, [""]] end else res = clazz.find(id) end else conditions = CGI.parse(env['QUERY_STRING']) res = clazz.all(:conditions => conditions) end return [200, {"Content-Type" => "text/xml"}, [res.to_xml]] rescue CouchFoo::DocumentNotFound => e # or an ActiveRecord exception return fail(404, 'Resource not found') rescue NameError return fail(400, "Class not found") end end def fail(code, message) return [code, {"Content-Type" => "text/xml"}, ["#{message}"]] end end