humaneq (owner)

Revisions

gist: 66941 Download_button fork
public
Public Clone URL: git://gist.github.com/66941.git
Embed All Files: show embed
coucher.rb #
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
#
# 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"}, ["<?xml version='1.0' encoding='UTF-8'?><nil />"]]
          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"},
            ["<?xml version='1.0' encoding='UTF-8'?><error>#{message}</error>"]]
  end
end