sinatra-rest-json 0.1 → 0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +23 -5
- data/lib/sinatra/rest_json.rb +47 -2
- data/sinatra-rest-json.gemspec +1 -1
- data/test/test_sinatra_rest_json.rb +68 -1
- metadata +1 -2
- data/lib/sinatra/rest-json.rb +0 -78
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c4081e93189dcd0b6bbc54a6b1ee169c5afc28a3
|
4
|
+
data.tar.gz: 3721f4624f2adb52b8e2ee6d797713bd8b0885f8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f4daf6ec26cc4fed06a496d6f07def6366ad4e25f695d1308ad2c42228681a3647d1ecd575c127cc03c4f9d2634c7d9747e4add7ac16b526df3935507db0b705
|
7
|
+
data.tar.gz: 3c12b6468e34c69cc155483fd9d954a658e22480cb4c1b1976b6fbe3d5f0696683e90f17358901eb1c9047a72f90cfe70f901da1295b5604ebf1007352ad98da
|
data/README.md
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
# Easy REST JSON APIs for Sinatra & Active Record
|
2
2
|
|
3
3
|
|
4
|
-
Getting started
|
4
|
+
## Getting started
|
5
5
|
|
6
|
-
|
6
|
+
### 1. Setup your Gemfile
|
7
7
|
|
8
8
|
```ruby
|
9
9
|
# Gemfile
|
@@ -15,7 +15,7 @@ gem "json"
|
|
15
15
|
|
16
16
|
```
|
17
17
|
|
18
|
-
|
18
|
+
### 2. Setup your Sinatra App
|
19
19
|
|
20
20
|
```ruby
|
21
21
|
require 'sinatra'
|
@@ -39,9 +39,9 @@ end
|
|
39
39
|
# Set up your REST routes
|
40
40
|
rest_json Product
|
41
41
|
```
|
42
|
-
|
42
|
+
### 3. Profit
|
43
43
|
|
44
|
-
|
44
|
+
#### Now your app automatically has the following routes which returns JSON data from your model:
|
45
45
|
|
46
46
|
- **GET** /products (all)
|
47
47
|
- **GET** /products/:id (find)
|
@@ -55,3 +55,21 @@ rest_json Product
|
|
55
55
|
*Note for POST/PUT operations the data parameters should be like so: { product: { name: "foo", price: 1 }}
|
56
56
|
|
57
57
|
|
58
|
+
### 4. Authentication
|
59
|
+
|
60
|
+
Basic support for authentication is provided like so:
|
61
|
+
|
62
|
+
```ruby
|
63
|
+
# inside your sinatra app
|
64
|
+
|
65
|
+
rest_json Product, :authenticate => {
|
66
|
+
:all => lambda { true }, # allowed
|
67
|
+
:find => lambda { true }, #allowed
|
68
|
+
:create => lambda { false }, #not authorized
|
69
|
+
:update => lambda { false }, #not authorized
|
70
|
+
:delete => lambda { false } #not authorized
|
71
|
+
}
|
72
|
+
```
|
73
|
+
|
74
|
+
You can pass in any ruby object that has a call method which returns a value (e.g. proc or lambda). Naturally you can drop in whatever authentication you'd like
|
75
|
+
|
data/lib/sinatra/rest_json.rb
CHANGED
@@ -6,18 +6,43 @@ module Sinatra
|
|
6
6
|
NOT_FOUND = { :errors => ["record doesn't exist"] }.to_json
|
7
7
|
MODEL_REGEX = /([A-Z0-9]{1}[a-z0-9]+)/
|
8
8
|
|
9
|
+
NO_AUTH = lambda { true }
|
10
|
+
DEFAULT_AUTH = {
|
11
|
+
:all => NO_AUTH,
|
12
|
+
:find => NO_AUTH,
|
13
|
+
:create => NO_AUTH,
|
14
|
+
:update => NO_AUTH,
|
15
|
+
:delete => NO_AUTH
|
16
|
+
}
|
17
|
+
|
9
18
|
def rest_json(model_class, opts = {})
|
10
19
|
model_name = model_class.name.scan(MODEL_REGEX).join("_").downcase
|
11
20
|
route_name = model_class.table_name
|
12
21
|
|
22
|
+
options = opts.clone
|
23
|
+
options[:authenticate] ||= {}
|
24
|
+
authenticate = DEFAULT_AUTH.merge(options[:authenticate])
|
25
|
+
|
13
26
|
# all
|
14
27
|
get "/#{route_name}" do
|
28
|
+
authorized = authenticate[:all].call
|
29
|
+
|
30
|
+
unless authorized
|
31
|
+
halt 401, "Not authorized\n"
|
32
|
+
end
|
33
|
+
|
15
34
|
content_type :json
|
16
35
|
"[" + model_class.all.collect { |m| m.to_json }.join(",") + "]"
|
17
36
|
end
|
18
37
|
|
19
38
|
# find
|
20
39
|
get "/#{route_name}/:id" do
|
40
|
+
authorized = authenticate[:find].call
|
41
|
+
|
42
|
+
unless authorized
|
43
|
+
halt 401, "Not authorized\n"
|
44
|
+
end
|
45
|
+
|
21
46
|
content_type :json
|
22
47
|
model = model_class.find(params[:id].to_i)
|
23
48
|
|
@@ -29,7 +54,13 @@ module Sinatra
|
|
29
54
|
end
|
30
55
|
|
31
56
|
# create
|
32
|
-
|
57
|
+
post "/#{route_name}" do
|
58
|
+
authorized = authenticate[:create].call
|
59
|
+
|
60
|
+
unless authorized
|
61
|
+
halt 401, "Not authorized\n"
|
62
|
+
end
|
63
|
+
|
33
64
|
content_type :json
|
34
65
|
|
35
66
|
model = model_class.new(params[model_name])
|
@@ -42,7 +73,13 @@ module Sinatra
|
|
42
73
|
end
|
43
74
|
|
44
75
|
# update
|
45
|
-
|
76
|
+
put "/#{route_name}/:id" do
|
77
|
+
authorized = authenticate[:update].call
|
78
|
+
|
79
|
+
unless authorized
|
80
|
+
halt 401, "Not authorized\n"
|
81
|
+
end
|
82
|
+
|
46
83
|
content_type :json
|
47
84
|
|
48
85
|
model = model_class.find(params[:id].to_i)
|
@@ -60,6 +97,13 @@ module Sinatra
|
|
60
97
|
|
61
98
|
# delete
|
62
99
|
delete "/#{route_name}/:id" do
|
100
|
+
|
101
|
+
authorized = authenticate[:delete].call
|
102
|
+
|
103
|
+
unless authorized
|
104
|
+
halt 401, "Not authorized\n"
|
105
|
+
end
|
106
|
+
|
63
107
|
content_type :json
|
64
108
|
|
65
109
|
model = model_class.find(params[:id].to_i)
|
@@ -74,5 +118,6 @@ module Sinatra
|
|
74
118
|
|
75
119
|
end
|
76
120
|
|
121
|
+
|
77
122
|
register REST
|
78
123
|
end
|
data/sinatra-rest-json.gemspec
CHANGED
@@ -4,7 +4,7 @@ require 'rack/test'
|
|
4
4
|
require "minitest/autorun"
|
5
5
|
|
6
6
|
require 'sinatra/base'
|
7
|
-
require 'sinatra/
|
7
|
+
require 'sinatra/rest_json'
|
8
8
|
require 'json'
|
9
9
|
|
10
10
|
require File.join(File.dirname(__FILE__), "helper")
|
@@ -15,6 +15,7 @@ class TestApp < Sinatra::Base
|
|
15
15
|
end
|
16
16
|
|
17
17
|
|
18
|
+
|
18
19
|
describe "app" do
|
19
20
|
include Rack::Test::Methods
|
20
21
|
|
@@ -103,5 +104,71 @@ describe "app" do
|
|
103
104
|
assert_equal FooModel.all.size, 0
|
104
105
|
end
|
105
106
|
end
|
107
|
+
end
|
108
|
+
|
109
|
+
|
110
|
+
class AuthenticatedTestApp < Sinatra::Base
|
111
|
+
register Sinatra::REST
|
112
|
+
rest_json FooModel, :authenticate => {
|
113
|
+
:all => lambda { true },
|
114
|
+
:find => lambda { true },
|
115
|
+
:create => lambda { false },
|
116
|
+
:update => lambda { false },
|
117
|
+
:delete => lambda { false }
|
118
|
+
}
|
119
|
+
end
|
120
|
+
|
121
|
+
describe "authenticated app" do
|
122
|
+
include Rack::Test::Methods
|
123
|
+
|
124
|
+
def app
|
125
|
+
AuthenticatedTestApp
|
126
|
+
end
|
127
|
+
|
128
|
+
before do
|
129
|
+
FooModel.destroy_all
|
130
|
+
end
|
131
|
+
|
132
|
+
|
133
|
+
describe "GET /" do
|
134
|
+
it "should allow all when data" do
|
135
|
+
FooModel.create(:name => "foo1")
|
136
|
+
|
137
|
+
get "/foo_models"
|
138
|
+
assert_equal last_response.status, 200
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
describe "GET /foo_models/:id" do
|
143
|
+
it "should allow finding a model" do
|
144
|
+
FooModel.create(:name => "foo1")
|
145
|
+
get "/foo_models/1"
|
146
|
+
assert_equal last_response.status, 200
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
describe "POST /foo_models" do
|
151
|
+
it "should not allow creation" do
|
152
|
+
assert_equal FooModel.all.size, 0
|
153
|
+
post "/foo_models", { :foo_model => { :name => "foo1" } }
|
154
|
+
assert_equal last_response.status, 401
|
155
|
+
end
|
156
|
+
end
|
106
157
|
|
158
|
+
|
159
|
+
describe "PUT /foo_models/:id" do
|
160
|
+
it "should not allow updating" do
|
161
|
+
FooModel.create(:name => "foo1")
|
162
|
+
put "/foo_models/1", { :foo_model => { :name => "boo" } }
|
163
|
+
assert_equal last_response.status, 401
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
describe "DELETE /foo_models/:id" do
|
168
|
+
it "should now allow deletion" do
|
169
|
+
FooModel.create(:name => "foo1")
|
170
|
+
delete "/foo_models/1"
|
171
|
+
assert_equal last_response.status, 401
|
172
|
+
end
|
173
|
+
end
|
107
174
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sinatra-rest-json
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '0.
|
4
|
+
version: '0.2'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joshua Carver
|
@@ -49,7 +49,6 @@ files:
|
|
49
49
|
- LICENSE
|
50
50
|
- README.md
|
51
51
|
- Rakefile
|
52
|
-
- lib/sinatra/rest-json.rb
|
53
52
|
- lib/sinatra/rest_json.rb
|
54
53
|
- sinatra-rest-json.gemspec
|
55
54
|
- test/helper.rb
|
data/lib/sinatra/rest-json.rb
DELETED
@@ -1,78 +0,0 @@
|
|
1
|
-
require 'sinatra/base'
|
2
|
-
require 'json'
|
3
|
-
|
4
|
-
module Sinatra
|
5
|
-
module REST
|
6
|
-
NOT_FOUND = { :errors => ["record doesn't exist"] }.to_json
|
7
|
-
MODEL_REGEX = /([A-Z0-9]{1}[a-z0-9]+)/
|
8
|
-
|
9
|
-
def rest_json(model_class, opts = {})
|
10
|
-
model_name = model_class.name.scan(MODEL_REGEX).join("_").downcase
|
11
|
-
route_name = model_class.table_name
|
12
|
-
|
13
|
-
# all
|
14
|
-
get "/#{route_name}" do
|
15
|
-
content_type :json
|
16
|
-
"[" + model_class.all.collect { |m| m.to_json }.join(",") + "]"
|
17
|
-
end
|
18
|
-
|
19
|
-
# find
|
20
|
-
get "/#{route_name}/:id" do
|
21
|
-
content_type :json
|
22
|
-
model = model_class.find(params[:id].to_i)
|
23
|
-
|
24
|
-
if model.nil?
|
25
|
-
NOT_FOUND
|
26
|
-
else
|
27
|
-
model.to_json
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
# create
|
32
|
-
post "/#{route_name}" do
|
33
|
-
content_type :json
|
34
|
-
|
35
|
-
model = model_class.new(params[model_name])
|
36
|
-
|
37
|
-
if model.save
|
38
|
-
model.to_json
|
39
|
-
else
|
40
|
-
{ :errors => model.errors }.to_json
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
# update
|
45
|
-
put "/#{route_name}/:id" do
|
46
|
-
content_type :json
|
47
|
-
|
48
|
-
model = model_class.find(params[:id].to_i)
|
49
|
-
|
50
|
-
if model.nil?
|
51
|
-
NOT_FOUND
|
52
|
-
else
|
53
|
-
if model.update_attributes(params[model_name])
|
54
|
-
model.to_json
|
55
|
-
else
|
56
|
-
{ :errors => model.errors }.to_json
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
# delete
|
62
|
-
delete "/#{route_name}/:id" do
|
63
|
-
content_type :json
|
64
|
-
|
65
|
-
model = model_class.find(params[:id].to_i)
|
66
|
-
|
67
|
-
if model.nil?
|
68
|
-
NOT_FOUND
|
69
|
-
else
|
70
|
-
model.destroy.to_json
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
end
|
76
|
-
|
77
|
-
register REST
|
78
|
-
end
|