roda-rest_api 1.4.5 → 2.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.document +5 -0
- data/Gemfile +10 -0
- data/README.md +302 -0
- data/Rakefile +22 -0
- data/VERSION +1 -0
- data/lib/roda/plugins/rest_api.rb +302 -250
- data/roda-rest_api.gemspec +61 -0
- data/test/rest_api_api_test.rb +76 -0
- data/test/rest_api_form_input_test.rb +31 -0
- data/test/rest_api_id_pattern_test.rb +56 -0
- data/test/rest_api_nested_test.rb +105 -0
- data/test/rest_api_perf_benchmark.rb +35 -0
- data/test/rest_api_permit_test.rb +117 -0
- data/test/rest_api_resource_test.rb +127 -0
- data/test/rest_api_routes_test.rb +61 -0
- data/test/rest_api_serialize_test.rb +81 -0
- data/test/rest_api_singleton_test.rb +52 -0
- data/test/rest_api_split_route_test.rb +30 -0
- data/test/rest_api_upgrade_test.rb +22 -0
- data/test/rest_api_wrapper_test.rb +92 -0
- data/test/test_helpers.rb +93 -0
- metadata +27 -48
@@ -0,0 +1,61 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
# stub: roda-rest_api 2.0.1 ruby lib
|
6
|
+
|
7
|
+
Gem::Specification.new do |s|
|
8
|
+
s.name = "roda-rest_api"
|
9
|
+
s.version = "2.0.1"
|
10
|
+
|
11
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
12
|
+
s.require_paths = ["lib"]
|
13
|
+
s.authors = ["Michel Benevento"]
|
14
|
+
s.date = "2015-06-29"
|
15
|
+
s.description = "Create restful API easily with the Roda framework"
|
16
|
+
s.email = "michelbenevento@yahoo.com"
|
17
|
+
s.extra_rdoc_files = [
|
18
|
+
"README.md"
|
19
|
+
]
|
20
|
+
s.files = [
|
21
|
+
".document",
|
22
|
+
"Gemfile",
|
23
|
+
"README.md",
|
24
|
+
"Rakefile",
|
25
|
+
"VERSION",
|
26
|
+
"lib/roda/plugins/rest_api.rb",
|
27
|
+
"lib/roda/rest_api.rb",
|
28
|
+
"roda-rest_api.gemspec",
|
29
|
+
"test/rest_api_api_test.rb",
|
30
|
+
"test/rest_api_form_input_test.rb",
|
31
|
+
"test/rest_api_id_pattern_test.rb",
|
32
|
+
"test/rest_api_nested_test.rb",
|
33
|
+
"test/rest_api_perf_benchmark.rb",
|
34
|
+
"test/rest_api_permit_test.rb",
|
35
|
+
"test/rest_api_resource_test.rb",
|
36
|
+
"test/rest_api_routes_test.rb",
|
37
|
+
"test/rest_api_serialize_test.rb",
|
38
|
+
"test/rest_api_singleton_test.rb",
|
39
|
+
"test/rest_api_split_route_test.rb",
|
40
|
+
"test/rest_api_upgrade_test.rb",
|
41
|
+
"test/rest_api_wrapper_test.rb",
|
42
|
+
"test/test_helpers.rb"
|
43
|
+
]
|
44
|
+
s.homepage = "http://github.com/beno/roda-rest_api"
|
45
|
+
s.licenses = ["MIT"]
|
46
|
+
s.rubygems_version = "2.4.5"
|
47
|
+
s.summary = "Restful resources for Roda"
|
48
|
+
|
49
|
+
if s.respond_to? :specification_version then
|
50
|
+
s.specification_version = 4
|
51
|
+
|
52
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
53
|
+
s.add_runtime_dependency(%q<roda>, ["~> 2"])
|
54
|
+
else
|
55
|
+
s.add_dependency(%q<roda>, ["~> 2"])
|
56
|
+
end
|
57
|
+
else
|
58
|
+
s.add_dependency(%q<roda>, ["~> 2"])
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require "test_helpers"
|
2
|
+
|
3
|
+
class RestApiApiTest < Minitest::Test
|
4
|
+
include TestHelpers
|
5
|
+
|
6
|
+
def setup
|
7
|
+
end
|
8
|
+
|
9
|
+
def test_api_version
|
10
|
+
app :rest_api do |r|
|
11
|
+
r.api do
|
12
|
+
r.version 1 do
|
13
|
+
'api version 1'
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
assert_equal 'api version 1', request.get('/api/v1').body
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_api_version_no_path
|
21
|
+
app :rest_api do |r|
|
22
|
+
r.api(path: '') do
|
23
|
+
r.version 1 do
|
24
|
+
'api version 1'
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
assert_equal 'api version 1', request.get('/v1').body
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_api_version_subdomain
|
32
|
+
app :rest_api do |r|
|
33
|
+
r.api(subdomain: 'api') do
|
34
|
+
r.version 1 do
|
35
|
+
'api version 1'
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
assert_equal 'api version 1', request.get('/api/v1', "HTTP_HOST" => "api.example.com").body
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_api_host_fail
|
43
|
+
app :rest_api do |r|
|
44
|
+
r.api(subdomain: 'api') do
|
45
|
+
r.version 1 do
|
46
|
+
'api version 1'
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
assert_equal 404, request.get('/api/v1', "HTTP_HOST" => "www.example.com").status
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_api_path_fail
|
54
|
+
app :rest_api do |r|
|
55
|
+
r.api do
|
56
|
+
r.version 1 do
|
57
|
+
'api version 1'
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
assert_equal 404, request.get('/v1').status
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_api_path_fail2
|
65
|
+
app :rest_api do |r|
|
66
|
+
r.api do
|
67
|
+
r.resource :foo do |foo|
|
68
|
+
foo.list {[]}
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
assert_equal 404, request.get('/foo').status
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require "test_helpers"
|
2
|
+
|
3
|
+
class RestApiFormInputTest < Minitest::Test
|
4
|
+
include TestHelpers
|
5
|
+
|
6
|
+
def setup
|
7
|
+
app :rest_api do |r|
|
8
|
+
r.resource :albums do |rsc|
|
9
|
+
rsc.save { |atts| Album.create_or_update(atts) }
|
10
|
+
rsc.permit :name
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_create
|
16
|
+
id, name = 1, 'bar'
|
17
|
+
album = Album.new(id, name)
|
18
|
+
response = request.post('/albums', params: {name: name})
|
19
|
+
assert_equal album.to_json, response.body
|
20
|
+
assert_equal 201, response.status
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_update
|
24
|
+
id, name = 12, 'foo'
|
25
|
+
album = Album.new(id, name)
|
26
|
+
assert_equal album.to_json, request.patch('/albums/12', params: {id: id, name: name}).body
|
27
|
+
assert_equal album.to_json, request.put('/albums/12', params: {id: id, name: name}).body
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require "test_helpers"
|
2
|
+
|
3
|
+
class RestApiIdPatternTest < Minitest::Test
|
4
|
+
include TestHelpers
|
5
|
+
|
6
|
+
def setup
|
7
|
+
app :rest_api do |r|
|
8
|
+
r.api id_pattern: /id([\d]+)/ do
|
9
|
+
r.resource :artists, id_pattern: /@([\d]+)/ do |rsc|
|
10
|
+
rsc.one { |atts| "ARTIST_#{atts[:id]}" }
|
11
|
+
r.resource :songs, id_pattern: /foo([\d]+)/ do |rsc|
|
12
|
+
rsc.one { |atts| "SONG_#{atts[:id]}" }
|
13
|
+
end
|
14
|
+
r.resource :concerts do |rsc| # need to be explicit
|
15
|
+
rsc.one { |atts| "CONCERT_#{atts[:id]}" }
|
16
|
+
end
|
17
|
+
end
|
18
|
+
r.resource :venues do |rsc|
|
19
|
+
rsc.one { |atts| "VENUE_#{atts[:id]}" }
|
20
|
+
end
|
21
|
+
r.resource :albums do |rsc|
|
22
|
+
rsc.save { |atts| "SAVE_ALBUM_#{atts[:id]}" }
|
23
|
+
rsc.routes :create, :update
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_complex_pattern
|
31
|
+
assert_equal "SAVE_ALBUM_12", request.put('api/albums/id12', params:{foo:'bar'}).body
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_failing_pattern
|
35
|
+
assert_equal 404, request.get('api/albums/12').status
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_pattern_override
|
39
|
+
assert_equal "ARTIST_12", request.get('api/artists/@12').body
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_nested
|
43
|
+
assert_equal "SONG_4", request.get('api/artists/@12/songs/foo4').body
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_nested_fallback
|
47
|
+
assert_equal "CONCERT_3", request.get('api/artists/@12/concerts/@3').body
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_fallback
|
51
|
+
assert_equal "VENUE_5", request.get('api/venues/id5').body
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
|
56
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
require "test_helpers"
|
2
|
+
|
3
|
+
class RestApiNestedTest < Minitest::Test
|
4
|
+
include TestHelpers
|
5
|
+
|
6
|
+
def setup
|
7
|
+
app :rest_api do |r|
|
8
|
+
r.resource :albums do |albums|
|
9
|
+
albums.list { |params| Album.find({} ) }
|
10
|
+
albums.one { |params| Album[params[:id]] }
|
11
|
+
albums.routes :index, :show
|
12
|
+
r.resource :songs do |songs|
|
13
|
+
songs.list { |params| Song.find({ :album_id => params[:parent_id]} ) }
|
14
|
+
songs.one { |params| Song[params[:id]] }
|
15
|
+
songs.routes :index, :show
|
16
|
+
end
|
17
|
+
r.resource :settings, singleton: true do |settings|
|
18
|
+
settings.one { |params| Settings[3] }
|
19
|
+
settings.save { |atts| Settings[3].save(atts) }
|
20
|
+
settings.routes :show, :update
|
21
|
+
settings.permit :name
|
22
|
+
end
|
23
|
+
r.resource :artwork, parent_key: :album_id do |artwork|
|
24
|
+
artwork.list { |params| Artwork.find(params) }
|
25
|
+
artwork.routes :index
|
26
|
+
end
|
27
|
+
r.resource :favorites, bare: true do |favorites|
|
28
|
+
favorites.list { |params| Favorite.find(params) }
|
29
|
+
favorites.one { |params| Favorite[params[:id]] }
|
30
|
+
favorites.routes :index, :show
|
31
|
+
r.resource :things do |things|
|
32
|
+
things.list { |params| Thing.find(params) }
|
33
|
+
things.one { |params| Thing[params[:id]] }
|
34
|
+
things.routes :index, :edit
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_album_index
|
44
|
+
assert_equal Album.find({}).to_json, request.get('/albums').body
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_album_show
|
48
|
+
assert_equal Album[10].to_json, request.get('/albums/10').body
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_album_fail
|
52
|
+
assert_equal 404, request.get('/albums/--').status
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_songs_index
|
56
|
+
assert_equal Song.find({:album_id => 12 }).to_json, request.get('/albums/12/songs').body
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_songs_show
|
60
|
+
assert_equal Song[10].to_json, request.get('/albums/12/songs/10').body
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_songs_fail
|
64
|
+
assert_equal 404, request.get('/albums/12/songs/--').status
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_singleton_update
|
68
|
+
id, name = 3, 'bar'
|
69
|
+
settings = Settings.new(id, name)
|
70
|
+
assert_equal settings.to_json, request.patch('/albums/12/settings', input: {name: name}.to_json).body
|
71
|
+
end
|
72
|
+
#
|
73
|
+
def test_favorites_index
|
74
|
+
assert_equal Favorite.find({}).to_json, request.get('/albums/favorites').body
|
75
|
+
end
|
76
|
+
|
77
|
+
def test_favorites_show
|
78
|
+
assert_equal Favorite[7].to_json, request.get('/albums/favorites/7').body
|
79
|
+
end
|
80
|
+
|
81
|
+
def test_filtered_default
|
82
|
+
assert_equal Song.find({:album_id => 9 }).to_json, request.get('/albums/9/songs').body
|
83
|
+
end
|
84
|
+
|
85
|
+
def test_filtered_custom
|
86
|
+
assert_equal Artwork.find({:album_id => 8 }).to_json, request.get('/albums/8/artwork').body
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_deep_nest_fail
|
90
|
+
assert_equal 404, request.get('/albums/favorites/4/things/3').status
|
91
|
+
end
|
92
|
+
|
93
|
+
def test_deep_nest
|
94
|
+
assert_equal Thing[3].to_json, request.get('/albums/favorites/things/3/edit').body
|
95
|
+
end
|
96
|
+
|
97
|
+
|
98
|
+
class Song < Mock ; end
|
99
|
+
class Settings < Mock ; end
|
100
|
+
class Favorite < Mock ; end
|
101
|
+
class Artwork < Mock ; end
|
102
|
+
class Thing < Mock ; end
|
103
|
+
|
104
|
+
|
105
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require "test_helpers"
|
2
|
+
require "minitest/benchmark"
|
3
|
+
|
4
|
+
class RestApiPerformanceTest < Minitest::Benchmark
|
5
|
+
include TestHelpers
|
6
|
+
|
7
|
+
def setup
|
8
|
+
app :rest_api do |r|
|
9
|
+
r.resource :albums do |rsc|
|
10
|
+
rsc.list { |params| Album.find(params) }
|
11
|
+
rsc.one { |params| Album[params[:id]] }
|
12
|
+
rsc.save { |atts| Album.create_or_update(atts) }
|
13
|
+
rsc.routes :show, :create
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def bench_show
|
19
|
+
assert_performance_linear 0.99 do |n|
|
20
|
+
n.times do
|
21
|
+
request.get('/albums/12').body
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def bench_create
|
27
|
+
assert_performance_linear 0.99 do |n|
|
28
|
+
n.times do
|
29
|
+
request.post('/albums', 'rack.input' => post_args({name: 'foo'})}).body
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
require "test_helpers"
|
2
|
+
|
3
|
+
class RestApiPermitTest < Minitest::Test
|
4
|
+
include TestHelpers
|
5
|
+
|
6
|
+
|
7
|
+
def test_index_permitted
|
8
|
+
app :rest_api do |r|
|
9
|
+
r.resource :albums do |albums|
|
10
|
+
albums.list { |params| Album.find(params) }
|
11
|
+
albums.routes :index
|
12
|
+
albums.permit :page
|
13
|
+
end
|
14
|
+
end
|
15
|
+
params = {page: '2'}
|
16
|
+
assert_equal Album.find(params).to_json, request.get('/albums', {'QUERY_STRING' => 'page=2'}).body
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
def test_index_not_permitted
|
21
|
+
app :rest_api do |r|
|
22
|
+
r.resource :albums do |albums|
|
23
|
+
albums.list { |params| Album.find(params) }
|
24
|
+
albums.routes :index
|
25
|
+
albums.permit :page
|
26
|
+
end
|
27
|
+
end
|
28
|
+
params = {page_ct: '2'}
|
29
|
+
assert_equal Album.find({}).to_json, request.get('/albums', {'QUERY_STRING' => 'page_ct=2'}).body
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_create_permitted
|
33
|
+
app :rest_api do |r|
|
34
|
+
r.resource :albums do |albums|
|
35
|
+
albums.save { |params| Album.create_or_update(params) }
|
36
|
+
albums.routes :create, :update
|
37
|
+
albums.permit :name, :price
|
38
|
+
end
|
39
|
+
end
|
40
|
+
atts = {name: 'name', price: 3}
|
41
|
+
album = Album.new(1, atts[:name], atts[:price])
|
42
|
+
assert_equal album.to_json, request.post('/albums', input: atts.to_json).body
|
43
|
+
assert_equal 201, request.post('/albums', input: atts.to_json).status
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_create_not_permitted
|
47
|
+
app :rest_api do |r|
|
48
|
+
r.resource :albums do |albums|
|
49
|
+
albums.save { |params| Album.create_or_update(params) }
|
50
|
+
albums.routes :create, :update
|
51
|
+
albums.permit :name
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
atts = {name: 'name', price: 3}
|
56
|
+
album = Album.new(1, atts[:name])
|
57
|
+
assert_equal album.to_json, request.post('/albums', input: atts.to_json).body
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_create_nested_single
|
61
|
+
app :rest_api do |r|
|
62
|
+
r.resource :albums do |albums|
|
63
|
+
albums.save { |params| Album.create_or_update(params) }
|
64
|
+
albums.routes :create, :update
|
65
|
+
albums.permit :name, {price: :amount}
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
atts = {name: 'name', price: {amount: 4}}
|
70
|
+
album = Album.new(1, atts[:name], atts[:price])
|
71
|
+
assert_equal album.to_json, request.post('/albums', input: atts.to_json).body
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_create_nested_array
|
75
|
+
app :rest_api do |r|
|
76
|
+
r.resource :albums do |albums|
|
77
|
+
albums.save { |params| Album.create_or_update(params) }
|
78
|
+
albums.routes :create, :update
|
79
|
+
albums.permit :name, {price: [:amount, :currency, :discount]}
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
atts = {name: 'name', price: {amount: 4}}
|
84
|
+
album = Album.new(1, atts[:name], atts[:price])
|
85
|
+
assert_equal album.to_json, request.post('/albums', input: atts.to_json).body
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_create_nested_single_not_permitted
|
89
|
+
app :rest_api do |r|
|
90
|
+
r.resource :albums do |albums|
|
91
|
+
albums.save { |params| Album.create_or_update(params) }
|
92
|
+
albums.routes :create, :update
|
93
|
+
albums.permit :name, {price: :total}
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
atts = {name: 'name', price: {amount: 4}}
|
98
|
+
album = Album.new(1, atts[:name], {})
|
99
|
+
assert_equal album.to_json, request.post('/albums', input: atts.to_json).body
|
100
|
+
end
|
101
|
+
|
102
|
+
def test_create_nested_array_not_permitted
|
103
|
+
app :rest_api do |r|
|
104
|
+
r.resource :albums do |albums|
|
105
|
+
albums.save { |params| Album.create_or_update(params) }
|
106
|
+
albums.routes :create, :update
|
107
|
+
albums.permit :name, {price: [:total, :currency, :discount]}
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
atts = {name: 'name', price: {amount: 4, currency:'foo'}}
|
112
|
+
album = Album.new(1, atts[:name], {currency:'foo'})
|
113
|
+
assert_equal album.to_json, request.post('/albums', input: atts.to_json).body
|
114
|
+
end
|
115
|
+
|
116
|
+
|
117
|
+
end
|