api_taster 0.4.8 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +22 -0
- data/api_taster.gemspec +1 -0
- data/app/controllers/api_taster/routes_controller.rb +3 -2
- data/app/helpers/api_taster/application_helper.rb +6 -0
- data/app/views/api_taster/routes/show.html.erb +7 -0
- data/lib/api_taster/form_builder.rb +2 -2
- data/lib/api_taster/mapper.rb +24 -9
- data/lib/api_taster/route.rb +17 -0
- data/lib/api_taster/version.rb +1 -1
- data/spec/controllers/api_taster/routes_controller_spec.rb +2 -0
- data/spec/dummy/config/routes.rb +1 -4
- data/spec/form_builder_spec.rb +3 -3
- data/spec/helpers/api_taster/application_helper_spec.rb +9 -0
- data/spec/mapper_spec.rb +26 -1
- data/spec/route_spec.rb +36 -18
- metadata +22 -4
data/README.md
CHANGED
@@ -34,6 +34,7 @@ In `routes.rb`, define parameters for each API endpoint after the normal routes
|
|
34
34
|
```ruby
|
35
35
|
if Rails.env.development?
|
36
36
|
ApiTaster.routes do
|
37
|
+
desc 'Get a __list__ of users'
|
37
38
|
get '/users'
|
38
39
|
|
39
40
|
post '/users', {
|
@@ -78,6 +79,27 @@ ApiTaster.routes do
|
|
78
79
|
end
|
79
80
|
```
|
80
81
|
|
82
|
+
### Commenting API Endpoints
|
83
|
+
|
84
|
+
Before each route definitions, you may use `desc` to add some comments. Markdown is supported.
|
85
|
+
|
86
|
+
```ruby
|
87
|
+
desc 'Get a __list__ of users'
|
88
|
+
get '/users'
|
89
|
+
```
|
90
|
+
|
91
|
+
### Metadata for API Endpoints
|
92
|
+
|
93
|
+
For each route definition, you may supply an optional third parameter (hash) as metadata:
|
94
|
+
|
95
|
+
```ruby
|
96
|
+
get '/users', {}, { :meta => 'data' }
|
97
|
+
```
|
98
|
+
|
99
|
+
The metadata option is useful for passing in arbitrary data for a route definition. For example, you could specify response expectations so that your test suite could tap into them.
|
100
|
+
|
101
|
+
Metadata for every route definition are stored in `ApiTaster::Route.metadata`. Please read the source code to find out how to get metadata for a particular route.
|
102
|
+
|
81
103
|
### Missing Route Definitions Detection
|
82
104
|
|
83
105
|
Instead of manually finding out which route definitions you need, API Taster provides a warning page that shows you all the missing definitions.
|
data/api_taster.gemspec
CHANGED
@@ -18,6 +18,7 @@ Gem::Specification.new do |s|
|
|
18
18
|
s.add_dependency 'jquery-rails'
|
19
19
|
s.add_dependency 'sass-rails'
|
20
20
|
s.add_dependency 'bootstrap-sass', '~> 2.0.3'
|
21
|
+
s.add_dependency 'redcarpet'
|
21
22
|
|
22
23
|
s.add_development_dependency 'rake'
|
23
24
|
s.add_development_dependency 'simplecov'
|
@@ -9,8 +9,9 @@ module ApiTaster
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def show
|
12
|
-
@route
|
13
|
-
@params
|
12
|
+
@route = Route.find(params[:id])
|
13
|
+
@params = Route.params_for(@route)
|
14
|
+
@comment = Route.comment_for(@route)
|
14
15
|
end
|
15
16
|
|
16
17
|
def missing_definitions
|
@@ -8,6 +8,13 @@
|
|
8
8
|
<% if @params.is_a?(Hash) && @params.has_key?(:undefined) %>
|
9
9
|
<%= render 'undefined_route', :route => @params[:undefined] %>
|
10
10
|
<% else %>
|
11
|
+
|
12
|
+
<% if @comment %>
|
13
|
+
<div class="well">
|
14
|
+
<%= markdown @comment %>
|
15
|
+
</div>
|
16
|
+
<% end %>
|
17
|
+
|
11
18
|
<% @params.each do |param| %>
|
12
19
|
<%= form_tag @route[:path], :method => @route[:verb], :class => 'well form-horizontal', :remote => true do %>
|
13
20
|
|
@@ -8,12 +8,12 @@ module ApiTaster
|
|
8
8
|
|
9
9
|
def initialize(params)
|
10
10
|
flush_output_buffer
|
11
|
-
@_buffer = '
|
11
|
+
@_buffer = ''
|
12
12
|
add_to_buffer(params)
|
13
13
|
end
|
14
14
|
|
15
15
|
def html
|
16
|
-
@_buffer
|
16
|
+
"<legend class=\"hero-legend\"></legend>#{@_buffer}"
|
17
17
|
end
|
18
18
|
|
19
19
|
private
|
data/lib/api_taster/mapper.rb
CHANGED
@@ -1,25 +1,31 @@
|
|
1
1
|
module ApiTaster
|
2
2
|
class Mapper
|
3
|
+
cattr_accessor :last_desc
|
4
|
+
|
3
5
|
class << self
|
4
|
-
def get(path, params = {})
|
5
|
-
map_method(:get, path, params)
|
6
|
+
def get(path, params = {}, metadata = {})
|
7
|
+
map_method(:get, path, params, metadata)
|
8
|
+
end
|
9
|
+
|
10
|
+
def post(path, params = {}, metadata = {})
|
11
|
+
map_method(:post, path, params, metadata)
|
6
12
|
end
|
7
13
|
|
8
|
-
def
|
9
|
-
map_method(:
|
14
|
+
def put(path, params = {}, metadata = {})
|
15
|
+
map_method(:put, path, params, metadata)
|
10
16
|
end
|
11
17
|
|
12
|
-
def
|
13
|
-
map_method(:
|
18
|
+
def delete(path, params = {}, metadata = {})
|
19
|
+
map_method(:delete, path, params, metadata)
|
14
20
|
end
|
15
21
|
|
16
|
-
def
|
17
|
-
|
22
|
+
def desc(text)
|
23
|
+
self.last_desc = text
|
18
24
|
end
|
19
25
|
|
20
26
|
private
|
21
27
|
|
22
|
-
def map_method(method, path, params)
|
28
|
+
def map_method(method, path, params, metadata)
|
23
29
|
route = Route.find_by_verb_and_path(method, path)
|
24
30
|
|
25
31
|
if route.nil?
|
@@ -31,6 +37,15 @@ module ApiTaster
|
|
31
37
|
else
|
32
38
|
Route.supplied_params[route[:id]] ||= []
|
33
39
|
Route.supplied_params[route[:id]] << ApiTaster.global_params.merge(params)
|
40
|
+
|
41
|
+
unless last_desc.nil?
|
42
|
+
Route.comments[route[:id]] = last_desc
|
43
|
+
self.last_desc = nil
|
44
|
+
end
|
45
|
+
|
46
|
+
if metadata.any?
|
47
|
+
Route.metadata[route[:id]] = metadata
|
48
|
+
end
|
34
49
|
end
|
35
50
|
end
|
36
51
|
end
|
data/lib/api_taster/route.rb
CHANGED
@@ -5,6 +5,8 @@ module ApiTaster
|
|
5
5
|
cattr_accessor :mappings
|
6
6
|
cattr_accessor :supplied_params
|
7
7
|
cattr_accessor :obsolete_definitions
|
8
|
+
cattr_accessor :comments
|
9
|
+
cattr_accessor :metadata
|
8
10
|
|
9
11
|
class << self
|
10
12
|
|
@@ -12,6 +14,8 @@ module ApiTaster
|
|
12
14
|
self.route_set = Rails.application.routes
|
13
15
|
self.supplied_params = {}
|
14
16
|
self.obsolete_definitions = []
|
17
|
+
self.comments = {}
|
18
|
+
self.metadata = {}
|
15
19
|
|
16
20
|
normalise_routes!
|
17
21
|
|
@@ -31,6 +35,7 @@ module ApiTaster
|
|
31
35
|
end
|
32
36
|
|
33
37
|
route_set.routes.each do |route|
|
38
|
+
next if route.app.is_a?(ActionDispatch::Routing::Mapper::Constraints)
|
34
39
|
next if route.app.is_a?(Sprockets::Environment)
|
35
40
|
next if route.app == ApiTaster::Engine
|
36
41
|
|
@@ -71,6 +76,18 @@ module ApiTaster
|
|
71
76
|
supplied_params[route[:id]].collect { |input| split_input(input, route) }
|
72
77
|
end
|
73
78
|
|
79
|
+
def comment_for(route)
|
80
|
+
unless undefined_route?(route)
|
81
|
+
self.comments[route[:id].to_i]
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def metadata_for(route)
|
86
|
+
unless undefined_route?(route)
|
87
|
+
self.metadata[route[:id].to_i]
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
74
91
|
def defined_definitions
|
75
92
|
routes.reject { |route| undefined_route?(route) }
|
76
93
|
end
|
data/lib/api_taster/version.rb
CHANGED
@@ -21,11 +21,13 @@ module ApiTaster
|
|
21
21
|
it "#show" do
|
22
22
|
Route.stub(:find).and_return(Route.new)
|
23
23
|
Route.stub(:params_for).and_return([])
|
24
|
+
Route.stub(:comment_for).and_return([])
|
24
25
|
|
25
26
|
get :show, :id => 1, :use_route => :api_taster
|
26
27
|
|
27
28
|
assigns(:route).should be_kind_of(Route)
|
28
29
|
assigns(:params).should be_kind_of(Array)
|
30
|
+
assigns(:comment).should be_kind_of(Array)
|
29
31
|
end
|
30
32
|
|
31
33
|
it "#missing_definitions" do
|
data/spec/dummy/config/routes.rb
CHANGED
@@ -10,14 +10,11 @@ Rails.application.routes.draw do
|
|
10
10
|
end
|
11
11
|
|
12
12
|
ApiTaster.routes do
|
13
|
-
ApiTaster.global_params = {
|
14
|
-
:version => 1
|
15
|
-
}
|
16
|
-
|
17
13
|
get '/i_dont_exist_anymore', {
|
18
14
|
:hello => 'world'
|
19
15
|
}
|
20
16
|
|
17
|
+
desc 'Get a __list__ of users.'
|
21
18
|
get '/users'
|
22
19
|
|
23
20
|
post '/users', {
|
data/spec/form_builder_spec.rb
CHANGED
@@ -48,12 +48,12 @@ module ApiTaster
|
|
48
48
|
end
|
49
49
|
|
50
50
|
it "does arrays" do
|
51
|
-
builder.html.should match(/name="
|
51
|
+
builder.html.should match(/name="user\[comment\]\[title\]\[\]" value="1"/)
|
52
52
|
end
|
53
53
|
|
54
54
|
it "does nested arrays" do
|
55
|
-
builder.html.should match(/name="
|
56
|
-
builder.html.should match(/name="
|
55
|
+
builder.html.should match(/name="items\[\]\[nested_items\]\[\]\[nested_numbers\]\[\]" value="5"/)
|
56
|
+
builder.html.should match(/name="items\[\]\[nested_items\]\[\]\[name\]" value="apple"/)
|
57
57
|
end
|
58
58
|
end
|
59
59
|
end
|
data/spec/mapper_spec.rb
CHANGED
@@ -46,9 +46,10 @@ module ApiTaster
|
|
46
46
|
|
47
47
|
before(:all) do
|
48
48
|
ApiTaster.routes do
|
49
|
+
desc "Dummy user ID"
|
49
50
|
get '/dummy_users/:id', :id => 1
|
50
51
|
post '/dummy_users'
|
51
|
-
post '/dummy_users', { :hello => 'world' }
|
52
|
+
post '/dummy_users', { :hello => 'world' }, { :meta => 'data' }
|
52
53
|
put '/dummy_users/:id', :id => 2
|
53
54
|
delete '/dummy_users/:id', :id => 3
|
54
55
|
end
|
@@ -79,5 +80,29 @@ module ApiTaster
|
|
79
80
|
|
80
81
|
Route.supplied_params[route[:id]].should == [{ :id => 3 }]
|
81
82
|
end
|
83
|
+
|
84
|
+
it "describes a route" do
|
85
|
+
route = Route.find_by_verb_and_path(:get, '/dummy_users/:id')
|
86
|
+
|
87
|
+
Route.comment_for(route).should == "Dummy user ID"
|
88
|
+
end
|
89
|
+
|
90
|
+
it "doesn't describe a route" do
|
91
|
+
route = Route.find_by_verb_and_path(:post, '/dummy_users')
|
92
|
+
|
93
|
+
Route.comment_for(route).should be_nil
|
94
|
+
end
|
95
|
+
|
96
|
+
it "meta data for a route" do
|
97
|
+
route = Route.find_by_verb_and_path(:post, '/dummy_users')
|
98
|
+
|
99
|
+
Route.metadata_for(route).should == { :meta => 'data' }
|
100
|
+
end
|
101
|
+
|
102
|
+
it "empty meta data for a route" do
|
103
|
+
route = Route.find_by_verb_and_path(:get, '/dummy_users')
|
104
|
+
|
105
|
+
Route.metadata_for(route).should == nil
|
106
|
+
end
|
82
107
|
end
|
83
108
|
end
|
data/spec/route_spec.rb
CHANGED
@@ -75,24 +75,42 @@ module ApiTaster
|
|
75
75
|
Route.find_by_verb_and_path(:delete, '/home').should == nil
|
76
76
|
end
|
77
77
|
|
78
|
-
|
79
|
-
|
80
|
-
:
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
Route.params_for(Route.find(
|
93
|
-
|
94
|
-
|
95
|
-
|
78
|
+
context "get data of a route" do
|
79
|
+
before do
|
80
|
+
Route.stub(:routes).and_return([{
|
81
|
+
:id => 0,
|
82
|
+
:path => '/dummy/:dummy_id'
|
83
|
+
}, {
|
84
|
+
:id => 999,
|
85
|
+
:path => 'a_non_existing_dummy',
|
86
|
+
:verb => 'get'
|
87
|
+
}])
|
88
|
+
Route.supplied_params[0] = [{ :dummy_id => 1, :hello => 'world' }]
|
89
|
+
end
|
90
|
+
|
91
|
+
it "#params_for" do
|
92
|
+
Route.params_for(Route.find(999)).should have_key(:undefined)
|
93
|
+
|
94
|
+
2.times do
|
95
|
+
Route.params_for(Route.find(0)).should == [{
|
96
|
+
:url_params => { :dummy_id => 1 },
|
97
|
+
:post_params => { :hello => 'world' }
|
98
|
+
}]
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
it "#comment_for" do
|
103
|
+
markdown_comment = "Heading\n=======\n * List item 1\n * List item 2"
|
104
|
+
Route.comments[0] = markdown_comment
|
105
|
+
|
106
|
+
Route.comment_for(Route.find(0)).should == markdown_comment
|
107
|
+
end
|
108
|
+
|
109
|
+
it "#metadata_for" do
|
110
|
+
metadata = { :hello => 'world' }
|
111
|
+
Route.metadata[0] = metadata
|
112
|
+
|
113
|
+
Route.metadata_for(Route.find(0)).should == metadata
|
96
114
|
end
|
97
115
|
end
|
98
116
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: api_taster
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-08-02 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rails
|
@@ -75,6 +75,22 @@ dependencies:
|
|
75
75
|
- - ~>
|
76
76
|
- !ruby/object:Gem::Version
|
77
77
|
version: 2.0.3
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: redcarpet
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :runtime
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
78
94
|
- !ruby/object:Gem::Dependency
|
79
95
|
name: rake
|
80
96
|
requirement: !ruby/object:Gem::Requirement
|
@@ -230,6 +246,7 @@ files:
|
|
230
246
|
- spec/dummy/log/.gitkeep
|
231
247
|
- spec/dummy/script/rails
|
232
248
|
- spec/form_builder_spec.rb
|
249
|
+
- spec/helpers/api_taster/application_helper_spec.rb
|
233
250
|
- spec/mapper_spec.rb
|
234
251
|
- spec/route_spec.rb
|
235
252
|
- spec/spec_helper.rb
|
@@ -466,7 +483,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
466
483
|
version: '0'
|
467
484
|
segments:
|
468
485
|
- 0
|
469
|
-
hash:
|
486
|
+
hash: -1701071876129671469
|
470
487
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
471
488
|
none: false
|
472
489
|
requirements:
|
@@ -475,7 +492,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
475
492
|
version: '0'
|
476
493
|
segments:
|
477
494
|
- 0
|
478
|
-
hash:
|
495
|
+
hash: -1701071876129671469
|
479
496
|
requirements: []
|
480
497
|
rubyforge_project:
|
481
498
|
rubygems_version: 1.8.24
|
@@ -727,6 +744,7 @@ test_files:
|
|
727
744
|
- spec/dummy/tmp/cache/sass/fced329c33ec1fff188d99efbc4d1fd1c556b66a/layout.css.scssc
|
728
745
|
- spec/dummy/tmp/pids/server.pid
|
729
746
|
- spec/form_builder_spec.rb
|
747
|
+
- spec/helpers/api_taster/application_helper_spec.rb
|
730
748
|
- spec/mapper_spec.rb
|
731
749
|
- spec/route_spec.rb
|
732
750
|
- spec/spec_helper.rb
|