json-crud-api 0.0.5 → 0.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/json-crud-api/api.rb +5 -65
- data/lib/json-crud-api/crud.rb +49 -51
- data/lib/json-crud-api/json_errors.rb +45 -0
- data/lib/json-crud-api/json_payload.rb +21 -0
- data/lib/json-crud-api/presenter.rb +26 -18
- data/lib/json-crud-api/session.rb +24 -0
- data/lib/json-crud-api.rb +5 -2
- data/spec/spec_helper.rb +9 -0
- data/spec/unit/api_spec.rb +11 -0
- data/spec/unit/auth_client_spec.rb +30 -30
- data/spec/unit/crud_spec.rb +331 -0
- data/spec/unit/json_errors_spec.rb +120 -0
- data/spec/unit/json_payload_spec.rb +65 -0
- data/spec/unit/presenter_spec.rb +88 -67
- data/spec/unit/service_spec.rb +54 -54
- data/spec/unit/session_spec.rb +120 -0
- metadata +22 -65
- data/spec/helper.rb +0 -12
- data/spec/helpers_spec.rb +0 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 449673186265d26d910abcbee096846f98b417ae
|
4
|
+
data.tar.gz: 8c11a8db9c5a320fa0da8ba9d373dca3a8f073e3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2845c4c9df02675b8c0a178f5c1d1f3c4b73e775ead310bfb296ba8cff3e1b6f37aa05526644ad8da71547a0af4e56722fef515027608827cadb68810a981586
|
7
|
+
data.tar.gz: 97f9dd8748df1a814977e2193df3830d8a85bcc24ff3892c6ed9d8f270b8c3b0525f68347797943de34ceeeb8da267e2045f24cea6c677db741385abd403541f
|
data/lib/json-crud-api/api.rb
CHANGED
@@ -4,7 +4,10 @@ require 'sinatra'
|
|
4
4
|
module JsonCrudApi
|
5
5
|
class API < Sinatra::Base
|
6
6
|
|
7
|
+
register JsonCrudApi::Session
|
8
|
+
register JsonCrudApi::JsonPayload
|
7
9
|
register JsonCrudApi::Crud
|
10
|
+
register JsonCrudApi::JsonErrors
|
8
11
|
|
9
12
|
before do
|
10
13
|
# HTTPS Only (if configured)
|
@@ -12,38 +15,14 @@ module JsonCrudApi
|
|
12
15
|
fail_with_error 403, 'SSL_ONLY', 'The API can only be accessed over SSL (HTTPS)'
|
13
16
|
end
|
14
17
|
|
15
|
-
# JSON Errors
|
16
|
-
@errors = []
|
17
|
-
|
18
18
|
# No-Cache by default
|
19
19
|
cache_control :no_cache, :max_age => 0
|
20
20
|
|
21
21
|
# Session
|
22
|
-
|
23
|
-
@logged_in = false
|
24
|
-
if settings.respond_to? :auth_client
|
25
|
-
@session_id = env['HTTP_X_SESSION_ID']
|
26
|
-
unless @session_id.nil?
|
27
|
-
@user = settings.auth_client.get(@session_id)
|
28
|
-
@logged_in = !@user.nil?
|
29
|
-
end
|
30
|
-
end
|
31
|
-
settings.services.each do |k,service|
|
32
|
-
service.set_user @user if service.respond_to? :set_user
|
33
|
-
end
|
22
|
+
process_session
|
34
23
|
|
35
24
|
# JSON Payload
|
36
|
-
|
37
|
-
body = request.body.read
|
38
|
-
if body.length > 2
|
39
|
-
begin
|
40
|
-
@payload = JSON.parse body, :symbolize_names => true
|
41
|
-
rescue JSON::ParserError
|
42
|
-
fail_with_error 422, 'JSON_PARSE_ERROR', 'The JSON payload cannot be parsed'
|
43
|
-
end
|
44
|
-
else
|
45
|
-
@payload = nil
|
46
|
-
end
|
25
|
+
process_json_payload
|
47
26
|
|
48
27
|
# CORS
|
49
28
|
content_type 'application/json; charset=utf-8'
|
@@ -51,45 +30,6 @@ module JsonCrudApi
|
|
51
30
|
response.headers['Access-Control-Allow-Headers'] = 'Content-Type'
|
52
31
|
end
|
53
32
|
|
54
|
-
def logged_in?
|
55
|
-
@logged_in
|
56
|
-
end
|
57
|
-
|
58
|
-
def add_error(code, message, reference = nil)
|
59
|
-
@errors = [] if @errors.nil?
|
60
|
-
|
61
|
-
error = {
|
62
|
-
:code => code,
|
63
|
-
:message => message,
|
64
|
-
}
|
65
|
-
error[:reference] = reference unless reference.nil?
|
66
|
-
@errors.push error
|
67
|
-
end
|
68
|
-
|
69
|
-
def fail_with_error(status, code, message, reference = nil)
|
70
|
-
add_error code,message,reference
|
71
|
-
fail_with_errors status
|
72
|
-
end
|
73
|
-
|
74
|
-
def fail_with_errors(status = 422)
|
75
|
-
halt status, JSON.fast_generate({
|
76
|
-
:success => false,
|
77
|
-
:errors => @errors
|
78
|
-
})
|
79
|
-
end
|
80
|
-
|
81
|
-
def fail_not_found
|
82
|
-
fail_with_error 404, 'NOT_FOUND','The resource cannot be found.'
|
83
|
-
end
|
84
|
-
|
85
|
-
def fail_unauthorized
|
86
|
-
fail_with_error 401, 'UNAUTHORIZED','Authorization is required to perform this operation on the resource.'
|
87
|
-
end
|
88
|
-
|
89
|
-
def fail_forbidden
|
90
|
-
fail_with_error 403, 'FORBIDDEN','The user is not allowed to perform this operation on the resource.'
|
91
|
-
end
|
92
|
-
|
93
33
|
not_found do
|
94
34
|
fail_not_found
|
95
35
|
end
|
data/lib/json-crud-api/crud.rb
CHANGED
@@ -1,71 +1,69 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
1
3
|
module JsonCrudApi
|
2
4
|
module Crud
|
3
5
|
|
4
6
|
def crud_api(url, key, options = [])
|
5
7
|
|
6
8
|
unless options.include? :disable_read
|
9
|
+
get url do crud_get_all(key) end unless options.include? :disable_get_all
|
10
|
+
get url+"/:id" do crud_get(key) end unless options.include? :disable_get
|
11
|
+
end
|
7
12
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
entities = service.get_all
|
14
|
-
fail_not_found if entities.nil?
|
13
|
+
unless options.include? :disable_write
|
14
|
+
post url do crud_post(key) end unless options.include? :disable_post
|
15
|
+
put url+"/:id" do crud_put(key) end unless options.include? :disable_put
|
16
|
+
delete url+"/:id" do crud_delete(key) end unless options.include? :disable_delete
|
17
|
+
end
|
15
18
|
|
16
|
-
|
17
|
-
end
|
18
|
-
end
|
19
|
+
end
|
19
20
|
|
20
|
-
|
21
|
-
get url+"/:id" do
|
22
|
-
service = settings.services[key]
|
23
|
-
presenter = settings.presenters[key]
|
24
|
-
fail_unauthorized unless service.user_authorized_for? :get
|
25
|
-
entity = service.get(params["id"])
|
26
|
-
fail_not_found if entity.nil?
|
21
|
+
private
|
27
22
|
|
28
|
-
|
29
|
-
|
30
|
-
|
23
|
+
def crud_get_all(key)
|
24
|
+
service = settings.services[key]
|
25
|
+
presenter = settings.presenters[key]
|
26
|
+
return fail_unauthorized unless service.user_authorized_for? :get_all
|
27
|
+
entities = service.get_all
|
28
|
+
return fail_not_found if entities.nil?
|
31
29
|
|
32
|
-
|
30
|
+
JSON.fast_generate presenter.render(entities, :get_all)
|
31
|
+
end
|
33
32
|
|
34
|
-
|
33
|
+
def crud_get(key)
|
34
|
+
service = settings.services[key]
|
35
|
+
presenter = settings.presenters[key]
|
36
|
+
return fail_unauthorized unless service.user_authorized_for? :get
|
37
|
+
entity = service.get(params["id"])
|
38
|
+
return fail_not_found if entity.nil?
|
35
39
|
|
36
|
-
|
37
|
-
|
38
|
-
service = settings.services[key]
|
39
|
-
presenter = settings.presenters[key]
|
40
|
-
fail_unauthorized unless service.user_authorized_for? :create
|
41
|
-
entity = service.create(presenter.parse(@payload, :post))
|
40
|
+
JSON.fast_generate presenter.render(entity, :get)
|
41
|
+
end
|
42
42
|
|
43
|
-
|
44
|
-
|
45
|
-
|
43
|
+
def crud_post(key)
|
44
|
+
service = settings.services[key]
|
45
|
+
presenter = settings.presenters[key]
|
46
|
+
return fail_unauthorized unless service.user_authorized_for? :create
|
47
|
+
entity = service.create(presenter.parse(@payload, :post))
|
46
48
|
|
47
|
-
|
48
|
-
|
49
|
-
service = settings.services[key]
|
50
|
-
presenter = settings.presenters[key]
|
51
|
-
fail_unauthorized unless service.user_authorized_for? :update
|
52
|
-
fail_not_found unless service.update(params["id"], presenter.parse(@payload, :put))
|
53
|
-
entity = service.get(params["id"])
|
54
|
-
JSON.fast_generate settings.presenters[key].render(entity, :put)
|
55
|
-
end
|
56
|
-
end
|
49
|
+
JSON.fast_generate presenter.render(entity, :post)
|
50
|
+
end
|
57
51
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
end
|
52
|
+
def crud_put(key)
|
53
|
+
service = settings.services[key]
|
54
|
+
presenter = settings.presenters[key]
|
55
|
+
return fail_unauthorized unless service.user_authorized_for? :update
|
56
|
+
return fail_not_found unless service.update(params["id"], presenter.parse(@payload, :put))
|
57
|
+
entity = service.get(params["id"])
|
58
|
+
JSON.fast_generate presenter.render(entity, :put)
|
59
|
+
end
|
67
60
|
|
68
|
-
|
61
|
+
def crud_delete(key)
|
62
|
+
service = settings.services[key]
|
63
|
+
presenter = settings.presenters[key]
|
64
|
+
return fail_unauthorized unless service.user_authorized_for? :delete
|
65
|
+
return fail_not_found unless service.delete(params["id"])
|
66
|
+
204
|
69
67
|
end
|
70
68
|
end
|
71
69
|
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module JsonCrudApi
|
4
|
+
module JsonErrors
|
5
|
+
|
6
|
+
def clear_errors
|
7
|
+
@errors = []
|
8
|
+
end
|
9
|
+
|
10
|
+
def add_error(code, message, reference = nil)
|
11
|
+
@errors = [] if @errors.nil?
|
12
|
+
|
13
|
+
error = {
|
14
|
+
:code => code,
|
15
|
+
:message => message,
|
16
|
+
}
|
17
|
+
error[:reference] = reference unless reference.nil?
|
18
|
+
@errors.push error
|
19
|
+
end
|
20
|
+
|
21
|
+
def fail_with_error(status, code, message, reference = nil)
|
22
|
+
add_error code,message,reference
|
23
|
+
fail_with_errors status
|
24
|
+
end
|
25
|
+
|
26
|
+
def fail_with_errors(status = 422)
|
27
|
+
halt status, JSON.fast_generate({
|
28
|
+
:success => false,
|
29
|
+
:errors => @errors
|
30
|
+
})
|
31
|
+
end
|
32
|
+
|
33
|
+
def fail_not_found
|
34
|
+
fail_with_error 404, 'NOT_FOUND','The resource cannot be found.'
|
35
|
+
end
|
36
|
+
|
37
|
+
def fail_unauthorized
|
38
|
+
fail_with_error 401, 'UNAUTHORIZED','Authorization is required to perform this operation on the resource.'
|
39
|
+
end
|
40
|
+
|
41
|
+
def fail_forbidden
|
42
|
+
fail_with_error 403, 'FORBIDDEN','The user is not allowed to perform this operation on the resource.'
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module JsonCrudApi
|
4
|
+
module JsonPayload
|
5
|
+
def process_json_payload
|
6
|
+
request.body.rewind
|
7
|
+
body = request.body.read
|
8
|
+
unless body.length > 2
|
9
|
+
@payload = nil
|
10
|
+
return
|
11
|
+
end
|
12
|
+
|
13
|
+
begin
|
14
|
+
@payload = JSON.parse body, :symbolize_names => true
|
15
|
+
rescue JSON::ParserError
|
16
|
+
@payload = nil
|
17
|
+
fail_with_error 422, 'JSON_PARSE_ERROR', 'The JSON payload cannot be parsed'
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -8,41 +8,49 @@ module JsonCrudApi
|
|
8
8
|
@exclude = options[:exclude]
|
9
9
|
@include = options[:include]
|
10
10
|
|
11
|
+
# Properties Cache
|
12
|
+
@properties = { :render => {}, :parse => {} }
|
13
|
+
|
11
14
|
throw "Model must be defined" if @model.nil?
|
12
15
|
end
|
13
16
|
|
14
17
|
def render(data, operation = nil)
|
15
18
|
return data.map {|d| render(d, operation) } if data.is_a?(Array)
|
16
19
|
|
17
|
-
|
20
|
+
unless @properties[:render].has_key? operation
|
21
|
+
@properties[:render][operation] = get_properties(:render, operation)
|
22
|
+
end
|
23
|
+
Hash[@properties[:render][operation].map { |p| [p, data.send(p)] }]
|
18
24
|
end
|
19
25
|
|
20
26
|
def parse(data, operation = nil)
|
21
27
|
return data.map {|d| parse(d, operation) } if data.is_a?(Array)
|
22
28
|
|
23
|
-
|
29
|
+
unless @properties[:parse].has_key? operation
|
30
|
+
@properties[:parse][operation] = get_properties(:parse, operation)
|
31
|
+
end
|
32
|
+
|
33
|
+
out = Hash.new
|
34
|
+
data.each_pair { |k,v| out[k] = v if @properties[:parse][operation].include?(k) }
|
35
|
+
out
|
24
36
|
end
|
25
37
|
|
26
38
|
def get_properties(method, operation)
|
27
39
|
properties = @model.properties.map { |p| p.name.to_sym }
|
28
|
-
unless @exclude.nil?
|
29
|
-
|
30
|
-
properties -= @exclude[operation] unless @exclude[operation].nil?
|
31
|
-
unless @exclude[method].nil?
|
32
|
-
properties -= @exclude[method][:all] unless @exclude[method][:all].nil?
|
33
|
-
properties -= @exclude[method][operation] unless @exclude[method][operation].nil?
|
34
|
-
end
|
35
|
-
end
|
36
|
-
unless @include.nil?
|
37
|
-
properties += @include[:all] unless @include[:all].nil?
|
38
|
-
properties += @include[operation] unless @include[operation].nil?
|
39
|
-
unless @include[method].nil?
|
40
|
-
properties += @include[method][:all] unless @include[method][:all].nil?
|
41
|
-
properties += @include[method][operation] unless @include[method][operation].nil?
|
42
|
-
end
|
43
|
-
end
|
40
|
+
properties -= filter_properties @exclude, method, operation unless @exclude.nil?
|
41
|
+
properties += filter_properties @include, method, operation unless @include.nil?
|
44
42
|
properties
|
45
43
|
end
|
46
44
|
|
45
|
+
def filter_properties(parameter, method, operation)
|
46
|
+
properties = []
|
47
|
+
properties += parameter[:all] unless parameter[:all].nil?
|
48
|
+
properties += parameter[operation] unless parameter[operation].nil?
|
49
|
+
unless parameter[method].nil?
|
50
|
+
properties += parameter[method][:all] unless parameter[method][:all].nil?
|
51
|
+
properties += parameter[method][operation] unless parameter[method][operation].nil?
|
52
|
+
end
|
53
|
+
properties
|
54
|
+
end
|
47
55
|
end
|
48
56
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module JsonCrudApi
|
4
|
+
module Session
|
5
|
+
def process_session
|
6
|
+
@user = nil
|
7
|
+
@logged_in = false
|
8
|
+
if settings.respond_to? :auth_client
|
9
|
+
@session_id = env['HTTP_X_SESSION_ID']
|
10
|
+
unless @session_id.nil?
|
11
|
+
@user = settings.auth_client.get(@session_id)
|
12
|
+
@logged_in = !@user.nil?
|
13
|
+
end
|
14
|
+
end
|
15
|
+
settings.services.each do |k,service|
|
16
|
+
service.set_user @user if service.respond_to? :set_user
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def logged_in?
|
21
|
+
@logged_in
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/lib/json-crud-api.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
|
+
require "json-crud-api/session"
|
1
2
|
require "json-crud-api/presenter"
|
2
3
|
require "json-crud-api/service"
|
3
4
|
require "json-crud-api/crud"
|
4
|
-
require "json-crud-api/
|
5
|
-
require "json-crud-api/
|
5
|
+
require "json-crud-api/json_payload"
|
6
|
+
require "json-crud-api/json_errors"
|
7
|
+
require "json-crud-api/auth_client"
|
8
|
+
require "json-crud-api/api"
|
data/spec/spec_helper.rb
ADDED
@@ -1,4 +1,4 @@
|
|
1
|
-
require "
|
1
|
+
require "spec_helper"
|
2
2
|
|
3
3
|
describe JsonCrudApi::AuthClient do
|
4
4
|
before(:each) do
|
@@ -13,89 +13,89 @@ describe JsonCrudApi::AuthClient do
|
|
13
13
|
|
14
14
|
describe '#initialize' do
|
15
15
|
it 'should inject dependencies correctly' do
|
16
|
-
@client.redis.
|
17
|
-
@client.session_ttl.
|
18
|
-
@client.prefix.
|
16
|
+
expect(@client.redis).to be @mock_redis
|
17
|
+
expect(@client.session_ttl).to be 200
|
18
|
+
expect(@client.prefix).to be 789
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
22
|
describe '#get' do
|
23
23
|
it 'should call get_redis_key and redis get' do
|
24
|
-
@client.
|
25
|
-
@mock_redis.
|
24
|
+
expect(@client).to receive(:get_redis_key).with('one')
|
25
|
+
expect(@mock_redis).to receive(:get).and_return nil
|
26
26
|
@client.get('one')
|
27
27
|
end
|
28
28
|
|
29
29
|
it 'should return nil if redis get return nil' do
|
30
|
-
@mock_redis.
|
31
|
-
@client.get('one').
|
30
|
+
expect(@mock_redis).to receive(:get).and_return nil
|
31
|
+
expect(@client.get('one')).to be_nil
|
32
32
|
end
|
33
33
|
|
34
34
|
it 'should call touch if redis get is non nil' do
|
35
|
-
@mock_redis.
|
36
|
-
@client.
|
35
|
+
expect(@mock_redis).to receive(:get).and_return '{}'
|
36
|
+
expect(@client).to receive(:touch).with('789one')
|
37
37
|
@client.get('one')
|
38
38
|
end
|
39
39
|
|
40
40
|
it 'should parse JSON from redis get' do
|
41
|
-
@mock_redis.
|
42
|
-
@client.
|
43
|
-
@client.get('one').
|
41
|
+
expect(@mock_redis).to receive(:get).and_return '{"five":5}'
|
42
|
+
expect(@client).to receive(:touch).with('789one')
|
43
|
+
expect(@client.get('one')).to eq({ :five => 5 })
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
47
47
|
describe '#delete' do
|
48
48
|
it 'should call get_redis_key and redis exists and return false if exists is false' do
|
49
|
-
@client.
|
50
|
-
@mock_redis.
|
51
|
-
@client.delete('one').
|
49
|
+
expect(@client).to receive(:get_redis_key).with('one')
|
50
|
+
expect(@mock_redis).to receive(:exists).and_return false
|
51
|
+
expect(@client.delete('one')).to be false
|
52
52
|
end
|
53
53
|
|
54
54
|
it 'should call redis del and return true if redis exists is true' do
|
55
|
-
@mock_redis.
|
56
|
-
@mock_redis.
|
57
|
-
@client.delete('one').
|
55
|
+
expect(@mock_redis).to receive(:exists).and_return true
|
56
|
+
expect(@mock_redis).to receive(:del).with('789one')
|
57
|
+
expect(@client.delete('one')).to be true
|
58
58
|
end
|
59
59
|
end
|
60
60
|
|
61
61
|
describe '#touch' do
|
62
62
|
it 'should call get_redis_key and redis exists and return false if exists is false' do
|
63
|
-
@client.
|
64
|
-
@mock_redis.
|
65
|
-
@client.touch('one').
|
63
|
+
expect(@client).to receive(:get_redis_key).with('one')
|
64
|
+
expect(@mock_redis).to receive(:exists).and_return false
|
65
|
+
expect(@client.touch('one')).to be false
|
66
66
|
end
|
67
67
|
|
68
68
|
it 'should call redis expire and return true if redis exists is true' do
|
69
|
-
@mock_redis.
|
70
|
-
@mock_redis.
|
71
|
-
@client.touch('one').
|
69
|
+
expect(@mock_redis).to receive(:exists).and_return true
|
70
|
+
expect(@mock_redis).to receive(:expire).with('789one', 200)
|
71
|
+
expect(@client.touch('one')).to be true
|
72
72
|
end
|
73
73
|
end
|
74
74
|
|
75
75
|
describe '#get_redis_key' do
|
76
76
|
it 'should return key if prefix is nil' do
|
77
77
|
@client.prefix = nil
|
78
|
-
@client.get_redis_key('one').
|
78
|
+
expect(@client.get_redis_key('one')).to eq 'one'
|
79
79
|
end
|
80
80
|
|
81
81
|
it 'should return key.to_s if prefix is nil' do
|
82
82
|
@client.prefix = nil
|
83
|
-
@client.get_redis_key(1).
|
83
|
+
expect(@client.get_redis_key(1)).to eq '1'
|
84
84
|
end
|
85
85
|
|
86
86
|
it 'should return prefix plus key if prefix is not nil' do
|
87
87
|
@client.prefix = 'pre-'
|
88
|
-
@client.get_redis_key('one').
|
88
|
+
expect(@client.get_redis_key('one')).to eq 'pre-one'
|
89
89
|
end
|
90
90
|
|
91
91
|
it 'should return prefix plus key.to_s if prefix is not nil' do
|
92
92
|
@client.prefix = 'post-'
|
93
|
-
@client.get_redis_key(1).
|
93
|
+
expect(@client.get_redis_key(1)).to eq 'post-1'
|
94
94
|
end
|
95
95
|
|
96
96
|
it 'should return prefix.to_s plus key.to_s if prefix is not nil' do
|
97
97
|
@client.prefix = 5
|
98
|
-
@client.get_redis_key(1).
|
98
|
+
expect(@client.get_redis_key(1)).to eq '51'
|
99
99
|
end
|
100
100
|
end
|
101
101
|
end
|