apipie-rails 0.0.24 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -1
- data/.travis.yml +6 -0
- data/CHANGELOG.md +97 -0
- data/Gemfile +1 -1
- data/Gemfile.rails30 +5 -0
- data/Gemfile.rails32 +5 -0
- data/Gemfile.rails40 +5 -0
- data/Gemfile.rails41 +5 -0
- data/README.rst +126 -11
- data/apipie-rails.gemspec +1 -1
- data/app/controllers/apipie/apipies_controller.rb +3 -0
- data/app/helpers/apipie_helper.rb +9 -0
- data/app/views/apipie/apipies/_metadata.erb +1 -0
- data/app/views/apipie/apipies/_method_detail.erb +46 -0
- data/app/views/apipie/apipies/_params.html.erb +12 -0
- data/app/views/apipie/apipies/_params_plain.html.erb +4 -0
- data/app/views/apipie/apipies/apipie_checksum.json.erb +1 -0
- data/app/views/apipie/apipies/method.html.erb +1 -37
- data/app/views/apipie/apipies/plain.html.erb +1 -0
- data/app/views/apipie/apipies/resource.html.erb +6 -37
- data/app/views/apipie/apipies/static.html.erb +1 -0
- data/lib/apipie/application.rb +16 -2
- data/lib/apipie/configuration.rb +8 -2
- data/lib/apipie/dsl_definition.rb +25 -6
- data/lib/apipie/error_description.rb +22 -10
- data/lib/apipie/extractor.rb +2 -1
- data/lib/apipie/extractor/writer.rb +8 -6
- data/lib/apipie/method_description.rb +7 -4
- data/lib/apipie/middleware/checksum_in_headers.rb +35 -0
- data/lib/apipie/param_description.rb +25 -4
- data/lib/apipie/resource_description.rb +8 -4
- data/lib/apipie/routing.rb +1 -0
- data/lib/apipie/validator.rb +71 -3
- data/lib/apipie/version.rb +1 -1
- data/lib/tasks/apipie.rake +26 -5
- data/spec/controllers/apipies_controller_spec.rb +2 -0
- data/spec/controllers/concerns_controller_spec.rb +1 -1
- data/spec/controllers/users_controller_spec.rb +130 -19
- data/spec/dummy/app/controllers/api/v1/architectures_controller.rb +1 -0
- data/spec/dummy/app/controllers/api/v2/nested/architectures_controller.rb +22 -20
- data/spec/dummy/app/controllers/concerns/sample_controller.rb +32 -30
- data/spec/dummy/app/controllers/users_controller.rb +18 -5
- data/spec/lib/method_description_spec.rb +22 -0
- data/spec/lib/param_description_spec.rb +77 -0
- data/spec/lib/rake_spec.rb +68 -0
- data/spec/lib/resource_description_spec.rb +18 -0
- data/spec/lib/validator_spec.rb +9 -0
- data/spec/spec_helper.rb +2 -1
- data/spec/support/rake.rb +21 -0
- metadata +20 -7
- data/CHANGELOG +0 -72
@@ -0,0 +1 @@
|
|
1
|
+
<pre class="prettyprint lang-yaml"><%= meta.to_yaml.gsub(/---\n/, "") %></pre>
|
@@ -0,0 +1,46 @@
|
|
1
|
+
<%= raw method[:full_description] %>
|
2
|
+
|
3
|
+
<% unless method[:formats].blank? %>
|
4
|
+
<%= heading('Supported Formats', h_level) %>
|
5
|
+
<%= method[:formats].join(', ') %>
|
6
|
+
<% end %>
|
7
|
+
|
8
|
+
<% unless method[:errors].blank? %>
|
9
|
+
<%= heading('Errors', h_level) %>
|
10
|
+
<% method[:errors].each do |err| %>
|
11
|
+
<%= err[:code] %>
|
12
|
+
<%= err[:description] %>
|
13
|
+
<br>
|
14
|
+
<% unless err[:metadata].blank? %>
|
15
|
+
Metadata:
|
16
|
+
<pre class="prettyprint lang-yaml"><%= err[:metadata].to_yaml %></pre>
|
17
|
+
<% end %>
|
18
|
+
<% end %>
|
19
|
+
<% end %>
|
20
|
+
|
21
|
+
<% unless method[:metadata].blank? %>
|
22
|
+
<%= heading('Metadata', h_level) %>
|
23
|
+
<%= render(:partial => "metadata", :locals => {:meta => method[:metadata]}) %>
|
24
|
+
<% end %>
|
25
|
+
|
26
|
+
<% unless method[:examples].blank? %>
|
27
|
+
<%= heading('Examples', h_level) %>
|
28
|
+
<% method[:examples].each do |example| %>
|
29
|
+
<pre class="prettyprint"><%= example %></pre>
|
30
|
+
<% end %>
|
31
|
+
<% end %>
|
32
|
+
|
33
|
+
<% unless method[:params].blank? %>
|
34
|
+
<%= heading('Params', h_level) %>
|
35
|
+
<table class='table'>
|
36
|
+
<thead>
|
37
|
+
<tr>
|
38
|
+
<th>Param name</th>
|
39
|
+
<th>Description</th>
|
40
|
+
</tr>
|
41
|
+
</thead>
|
42
|
+
<tbody>
|
43
|
+
<%= render(:partial => "params", :locals => {:params => method[:params]}) %>
|
44
|
+
</tbody>
|
45
|
+
</table>
|
46
|
+
<% end %>
|
@@ -1,6 +1,10 @@
|
|
1
1
|
<% level ||= 0 %>
|
2
2
|
<% col = 255 - level * 5 %>
|
3
3
|
<% params.each do |param| %>
|
4
|
+
<% if !param[:show] %>
|
5
|
+
<%= render(:partial => "params", :locals => {:level => level, :params => param[:params]}) unless param[:params].blank? %>
|
6
|
+
<% next %>
|
7
|
+
<% end %>
|
4
8
|
<tr style='background-color:rgb(<%= "#{col},#{col},#{col}" %>);'>
|
5
9
|
<td>
|
6
10
|
<strong><%= param[:full_name] %> </strong><br>
|
@@ -15,7 +19,15 @@
|
|
15
19
|
<br>
|
16
20
|
Value: <%= param[:validator] %>
|
17
21
|
<% end %>
|
22
|
+
|
23
|
+
<% unless param[:metadata].blank? %>
|
24
|
+
<br>
|
25
|
+
Metadata:
|
26
|
+
<%= render(:partial => "metadata", :locals => {:meta => param[:metadata]}) %>
|
27
|
+
<% end %>
|
28
|
+
|
18
29
|
</td>
|
30
|
+
|
19
31
|
</tr>
|
20
32
|
|
21
33
|
<%= render(:partial => "params", :locals => {:level => level + 1, :params => param[:params]}) unless param[:params].blank? %>
|
@@ -0,0 +1 @@
|
|
1
|
+
{ "checksum": "<%= raw Apipie.checksum %>" }
|
@@ -27,43 +27,7 @@
|
|
27
27
|
Also see <%= @method[:see].map { |s| link_to(s[:description], "#{s[:link]}.html") }.to_sentence.html_safe %>.
|
28
28
|
<% end %>
|
29
29
|
|
30
|
-
<%=
|
31
|
-
|
32
|
-
<% unless @method[:examples].blank? %>
|
33
|
-
<h2>Examples</h2>
|
34
|
-
<% @method[:examples].each do |example| %>
|
35
|
-
<pre class="prettyprint"><%= example %></pre>
|
36
|
-
<% end %>
|
37
|
-
<% end %>
|
38
|
-
|
39
|
-
<% unless @method[:formats].blank? %>
|
40
|
-
<h2>Supported Formats</h2>
|
41
|
-
<%= @method[:formats].join(', ') %>
|
42
|
-
<% end %>
|
43
|
-
|
44
|
-
<% unless @method[:errors].blank? %>
|
45
|
-
<h2>Errors</h2>
|
46
|
-
<% @method[:errors].each do |err| %>
|
47
|
-
<%= err[:code] %>
|
48
|
-
<%= err[:description] %>
|
49
|
-
<br>
|
50
|
-
<% end %>
|
51
|
-
<% end %>
|
52
|
-
|
53
|
-
<% unless @method[:params].blank? %>
|
54
|
-
<h2>Params</h2>
|
55
|
-
<table class='table'>
|
56
|
-
<thead>
|
57
|
-
<tr>
|
58
|
-
<th>Param name</th>
|
59
|
-
<th>Description</th>
|
60
|
-
</tr>
|
61
|
-
</thead>
|
62
|
-
<tbody>
|
63
|
-
<%= render(:partial => "params", :locals => {:params => @method[:params]}) %>
|
64
|
-
</tbody>
|
65
|
-
</table>
|
66
|
-
<% end %>
|
30
|
+
<%= render(:partial => "method_detail", :locals => {:method => @method, :h_level => 2}) %>
|
67
31
|
</div>
|
68
32
|
|
69
33
|
<% content_for :apipie_footer do %>
|
@@ -21,6 +21,11 @@
|
|
21
21
|
<div><%= raw @resource[:full_description] %></div>
|
22
22
|
<% end %>
|
23
23
|
|
24
|
+
<% unless @resource[:metadata].blank? %>
|
25
|
+
<h2>Metadata</h2>
|
26
|
+
<%= render(:partial => "metadata", :locals => {:meta => @resource[:metadata]}) %>
|
27
|
+
<% end %>
|
28
|
+
|
24
29
|
<% unless @resource[:formats].blank? %>
|
25
30
|
<h2>Supported Formats</h2>
|
26
31
|
<%= @resource[:formats].join(', ') %>
|
@@ -52,43 +57,7 @@
|
|
52
57
|
<% end %>
|
53
58
|
|
54
59
|
<div id='description-<%= m[:name] %>' class='collapse accordion-body'>
|
55
|
-
<%=
|
56
|
-
|
57
|
-
<% unless m[:formats].blank? %>
|
58
|
-
<h3>Supported Formats</h3>
|
59
|
-
<%= m[:formats].join(', ') %>
|
60
|
-
<% end %>
|
61
|
-
|
62
|
-
<% unless m[:errors].blank? %>
|
63
|
-
<h3>Errors</h3>
|
64
|
-
<% m[:errors].each do |err| %>
|
65
|
-
<%= err[:code] %>
|
66
|
-
<%= err[:description] %>
|
67
|
-
<br>
|
68
|
-
<% end %>
|
69
|
-
<% end %>
|
70
|
-
|
71
|
-
<% unless m[:examples].blank? %>
|
72
|
-
<h3>Examples</h3>
|
73
|
-
<% m[:examples].each do |example| %>
|
74
|
-
<pre class="prettyprint"><%= example %></pre>
|
75
|
-
<% end %>
|
76
|
-
<% end %>
|
77
|
-
|
78
|
-
<% unless m[:params].blank? %>
|
79
|
-
<h3>Params</h3>
|
80
|
-
<table class='table'>
|
81
|
-
<thead>
|
82
|
-
<tr>
|
83
|
-
<th>Param name</th>
|
84
|
-
<th>Description</th>
|
85
|
-
</tr>
|
86
|
-
</thead>
|
87
|
-
<tbody>
|
88
|
-
<%= render(:partial => "params", :locals => {:params => m[:params]}) %>
|
89
|
-
</tbody>
|
90
|
-
</table>
|
91
|
-
<% end %>
|
60
|
+
<%= render(:partial => "method_detail", :locals => {:method => m, :h_level => 3}) %>
|
92
61
|
</div>
|
93
62
|
<% end %>
|
94
63
|
</div>
|
data/lib/apipie/application.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
require 'apipie/static_dispatcher'
|
2
2
|
require 'yaml'
|
3
|
+
require 'digest/md5'
|
4
|
+
require 'json'
|
3
5
|
|
4
6
|
module Apipie
|
5
7
|
|
@@ -208,8 +210,8 @@ module Apipie
|
|
208
210
|
tape_file = File.join(Rails.root,"doc","apipie_examples.yml")
|
209
211
|
if File.exists?(tape_file)
|
210
212
|
#if SafeYAML gem is enabled, it will load examples as an array of Hash, instead of hash
|
211
|
-
if defined?
|
212
|
-
@recorded_examples =
|
213
|
+
if YAML.respond_to?(:safe_load_file) && defined?(SafeYAML)
|
214
|
+
@recorded_examples = SafeYAML.load_file(tape_file, :safe=>false)
|
213
215
|
else
|
214
216
|
@recorded_examples = YAML.load_file(tape_file)
|
215
217
|
end
|
@@ -264,6 +266,18 @@ module Apipie
|
|
264
266
|
api_controllers_paths.each do |f|
|
265
267
|
load_controller_from_file f
|
266
268
|
end
|
269
|
+
@checksum = compute_checksum if Apipie.configuration.update_checksum
|
270
|
+
end
|
271
|
+
|
272
|
+
def compute_checksum
|
273
|
+
all_docs = Apipie.available_versions.inject({}) do |all, version|
|
274
|
+
all.update(version => Apipie.to_json(version))
|
275
|
+
end
|
276
|
+
Digest::MD5.hexdigest(JSON.dump(all_docs))
|
277
|
+
end
|
278
|
+
|
279
|
+
def checksum
|
280
|
+
@checksum ||= compute_checksum
|
267
281
|
end
|
268
282
|
|
269
283
|
# Is there a reason to interpret the DSL for this run?
|
data/lib/apipie/configuration.rb
CHANGED
@@ -4,8 +4,8 @@ module Apipie
|
|
4
4
|
attr_accessor :app_name, :app_info, :copyright, :markup, :disqus_shortname,
|
5
5
|
:api_base_url, :doc_base_url, :required_by_default, :layout,
|
6
6
|
:default_version, :debug, :version_in_url, :namespaced_resources,
|
7
|
-
:validate, :validate_value, :validate_presence, :authenticate, :doc_path
|
8
|
-
|
7
|
+
:validate, :validate_value, :validate_presence, :authenticate, :doc_path,
|
8
|
+
:show_all_examples, :process_params, :update_checksum, :checksum_path
|
9
9
|
|
10
10
|
alias_method :validate?, :validate
|
11
11
|
alias_method :required_by_default?, :required_by_default
|
@@ -36,6 +36,9 @@ module Apipie
|
|
36
36
|
end
|
37
37
|
alias_method :validate_presence?, :validate_presence
|
38
38
|
|
39
|
+
def process_value?
|
40
|
+
@process_params
|
41
|
+
end
|
39
42
|
# set to true if you want to use pregenerated documentation cache and avoid
|
40
43
|
# generating the documentation on runtime (usefull for production
|
41
44
|
# environment).
|
@@ -124,6 +127,9 @@ module Apipie
|
|
124
127
|
@version_in_url = true
|
125
128
|
@namespaced_resources = false
|
126
129
|
@doc_path = "doc"
|
130
|
+
@process_params = false
|
131
|
+
@checksum_path = [@doc_base_url, '/api/']
|
132
|
+
@update_checksum = false
|
127
133
|
end
|
128
134
|
end
|
129
135
|
end
|
@@ -6,7 +6,7 @@ module Apipie
|
|
6
6
|
module DSL
|
7
7
|
|
8
8
|
module Base
|
9
|
-
attr_reader :apipie_resource_descriptions
|
9
|
+
attr_reader :apipie_resource_descriptions, :api_params
|
10
10
|
|
11
11
|
private
|
12
12
|
|
@@ -29,7 +29,8 @@ module Apipie
|
|
29
29
|
:examples => [],
|
30
30
|
:see => [],
|
31
31
|
:formats => nil,
|
32
|
-
:api_versions => []
|
32
|
+
:api_versions => [],
|
33
|
+
:meta => nil
|
33
34
|
}
|
34
35
|
end
|
35
36
|
end
|
@@ -76,7 +77,7 @@ module Apipie
|
|
76
77
|
# Example:
|
77
78
|
# api :GET, "/resource_route", "short description",
|
78
79
|
#
|
79
|
-
def api(method, path, desc = nil) #:doc:
|
80
|
+
def api(method, path, desc = nil, options={}) #:doc:
|
80
81
|
return unless Apipie.active_dsl?
|
81
82
|
_apipie_dsl_data[:api_args] << [method, path, desc]
|
82
83
|
end
|
@@ -164,20 +165,27 @@ module Apipie
|
|
164
165
|
_apipie_dsl_data[:formats] = formats
|
165
166
|
end
|
166
167
|
|
168
|
+
# Describe additional metadata
|
169
|
+
#
|
170
|
+
# meta :author => { :name => 'John', :surname => 'Doe' }
|
171
|
+
def meta(meta) #:doc:
|
172
|
+
_apipie_dsl_data[:meta] = meta
|
173
|
+
end
|
174
|
+
|
167
175
|
|
168
176
|
# Describe possible errors
|
169
177
|
#
|
170
178
|
# Example:
|
171
|
-
# error :desc => "speaker is sleeping", :code => 500
|
179
|
+
# error :desc => "speaker is sleeping", :code => 500, :meta => [:some, :more, :data]
|
172
180
|
# error 500, "speaker is sleeping"
|
173
181
|
# def hello_world
|
174
182
|
# return 500 if self.speaker.sleeping?
|
175
183
|
# puts "hello world"
|
176
184
|
# end
|
177
185
|
#
|
178
|
-
def error(
|
186
|
+
def error(code_or_options, desc=nil, options={}) #:doc:
|
179
187
|
return unless Apipie.active_dsl?
|
180
|
-
_apipie_dsl_data[:errors] <<
|
188
|
+
_apipie_dsl_data[:errors] << [code_or_options, desc, options]
|
181
189
|
end
|
182
190
|
|
183
191
|
def _apipie_define_validators(description)
|
@@ -186,6 +194,8 @@ module Apipie
|
|
186
194
|
|
187
195
|
old_method = instance_method(description.method)
|
188
196
|
|
197
|
+
|
198
|
+
# @todo we should use before_filter
|
189
199
|
define_method(description.method) do |*args|
|
190
200
|
|
191
201
|
if Apipie.configuration.validate_presence?
|
@@ -202,6 +212,15 @@ module Apipie
|
|
202
212
|
end
|
203
213
|
end
|
204
214
|
|
215
|
+
if Apipie.configuration.process_value?
|
216
|
+
@api_params = {}
|
217
|
+
|
218
|
+
description.params.each do |_, param|
|
219
|
+
# params processing
|
220
|
+
@api_params[param.as] = param.process_value(params[:"#{param.name}"]) if params.has_key?(param.name)
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
205
224
|
# run the original method code
|
206
225
|
old_method.bind(self).call(*args)
|
207
226
|
end
|
@@ -2,22 +2,34 @@ module Apipie
|
|
2
2
|
|
3
3
|
class ErrorDescription
|
4
4
|
|
5
|
-
attr_reader :code, :description
|
5
|
+
attr_reader :code, :description, :metadata
|
6
6
|
|
7
|
-
def
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
7
|
+
def self.from_dsl_data(args)
|
8
|
+
code_or_options, desc, options = args
|
9
|
+
Apipie::ErrorDescription.new(code_or_options,
|
10
|
+
desc,
|
11
|
+
options)
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(code_or_options, desc=nil, options={})
|
15
|
+
if code_or_options.is_a? Hash
|
16
|
+
code_or_options.symbolize_keys!
|
17
|
+
@code = code_or_options[:code]
|
18
|
+
@metadata = code_or_options[:meta]
|
19
|
+
@description = code_or_options[:desc] || code_or_options[:description]
|
12
20
|
else
|
13
|
-
|
21
|
+
@code = code_or_options
|
22
|
+
@metadata = options[:meta]
|
23
|
+
@description = desc
|
14
24
|
end
|
15
|
-
@code = args[:code] || args['code']
|
16
|
-
@description = args[:desc] || args[:description] || args['desc'] || args['description']
|
17
25
|
end
|
18
26
|
|
19
27
|
def to_json
|
20
|
-
{
|
28
|
+
{
|
29
|
+
:code => code,
|
30
|
+
:description => description,
|
31
|
+
:metadata => metadata
|
32
|
+
}
|
21
33
|
end
|
22
34
|
|
23
35
|
end
|
data/lib/apipie/extractor.rb
CHANGED
@@ -86,7 +86,8 @@ module Apipie
|
|
86
86
|
controller_path, action = route[:controller], route[:action]
|
87
87
|
next unless controller_path && action
|
88
88
|
|
89
|
-
|
89
|
+
controller_path = controller_path.split('::').map(&:camelize).join('::')
|
90
|
+
controller = "#{controller_path}Controller"
|
90
91
|
|
91
92
|
path = if /^#{Regexp.escape(api_prefix)}(.*)$/ =~ route[:path]
|
92
93
|
$1.sub!(/\(\.:format\)$/,"")
|
@@ -84,7 +84,9 @@ module Apipie
|
|
84
84
|
method_descriptions = Apipie.get_method_descriptions(call[:controller], call[:action])
|
85
85
|
call[:versions] = method_descriptions.map(&:version)
|
86
86
|
|
87
|
-
if
|
87
|
+
if Apipie.configuration.show_all_examples
|
88
|
+
show_in_doc = 1
|
89
|
+
elsif call[:versions].any? { |v| ! showed_in_versions.include?(v) }
|
88
90
|
call[:versions].each { |v| showed_in_versions << v }
|
89
91
|
show_in_doc = 1
|
90
92
|
else
|
@@ -99,11 +101,11 @@ module Apipie
|
|
99
101
|
|
100
102
|
def load_old_examples
|
101
103
|
if File.exists?(@examples_file)
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
104
|
+
if defined? SafeYAML
|
105
|
+
return YAML.load_file(@examples_file, :safe=>false)
|
106
|
+
else
|
107
|
+
return YAML.load_file(@examples_file)
|
108
|
+
end
|
107
109
|
end
|
108
110
|
return {}
|
109
111
|
end
|