apipie-rails 0.2.6 → 0.3.0

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.
@@ -5,12 +5,13 @@ module Apipie
5
5
 
6
6
  class Api
7
7
 
8
- attr_accessor :short_description, :path, :http_method, :options
8
+ attr_accessor :short_description, :path, :http_method, :from_routes, :options
9
9
 
10
10
  def initialize(method, path, desc, options)
11
11
  @http_method = method.to_s
12
12
  @path = path
13
13
  @short_description = desc
14
+ @from_routes = options[:from_routes]
14
15
  @options = options
15
16
  end
16
17
 
@@ -104,7 +105,10 @@ module Apipie
104
105
  end
105
106
 
106
107
  def create_api_url(api)
107
- path = "#{@resource._api_base_url}#{api.path}"
108
+ path = api.path
109
+ unless api.from_routes
110
+ path = "#{@resource._api_base_url}#{path}"
111
+ end
108
112
  path = path[0..-2] if path[-1..-1] == '/'
109
113
  return path
110
114
  end
@@ -174,7 +178,9 @@ module Apipie
174
178
  end
175
179
 
176
180
  def format_example(ex)
177
- example = "#{ex[:verb]} #{ex[:path]}"
181
+ example = ""
182
+ example << "// #{ex[:title]}\n" if ex[:title].present?
183
+ example << "#{ex[:verb]} #{ex[:path]}"
178
184
  example << "?#{ex[:query]}" unless ex[:query].blank?
179
185
  example << "\n" << format_example_data(ex[:request_data]).to_s if ex[:request_data]
180
186
  example << "\n" << ex[:code].to_s
@@ -0,0 +1,33 @@
1
+ module Apipie
2
+ class RoutesFormatter
3
+ API_METHODS = %w{GET POST PUT PATCH OPTIONS DELETE}
4
+
5
+ # The entry method called by Apipie to extract the array
6
+ # representing the api dsl from the routes definition.
7
+ def format_routes(rails_routes, args)
8
+ rails_routes.map { |rails_route| format_route(rails_route, args) }
9
+ end
10
+
11
+ def format_route(rails_route, args)
12
+ { :path => format_path(rails_route),
13
+ :verb => format_verb(rails_route),
14
+ :desc => args[:desc],
15
+ :options => args[:options] }
16
+ end
17
+
18
+ def format_path(rails_route)
19
+ rails_route.path.spec.to_s.gsub('(.:format)', '')
20
+ end
21
+
22
+ def format_verb(rails_route)
23
+ verb = API_METHODS.select{|defined_verb| defined_verb =~ /\A#{rails_route.verb}\z/}
24
+ if verb.count != 1
25
+ verb = API_METHODS.select{|defined_verb| defined_verb == rails_route.constraints[:method]}
26
+ if verb.blank?
27
+ raise "Unknow verb #{rails_route.path.spec.to_s}"
28
+ end
29
+ end
30
+ verb.first
31
+ end
32
+ end
33
+ end
@@ -407,6 +407,10 @@ module Apipie
407
407
  end
408
408
  end
409
409
 
410
+ def expected_type
411
+ 'boolean'
412
+ end
413
+
410
414
  def description
411
415
  "Must be 'true' or 'false'"
412
416
  end
@@ -444,6 +448,10 @@ module Apipie
444
448
  self.new(param_description, block, options[:param_group]) if block.is_a?(Proc) && block.arity <= 0 && argument == Array
445
449
  end
446
450
 
451
+ def expected_type
452
+ 'array'
453
+ end
454
+
447
455
  def description
448
456
  "Must be an Array of nested elements"
449
457
  end
@@ -1,3 +1,3 @@
1
1
  module Apipie
2
- VERSION = '0.2.6'
2
+ VERSION = '0.3.0'
3
3
  end
@@ -68,6 +68,8 @@ namespace :apipie do
68
68
  puts "#{Time.now} | Processing docs for #{lang}"
69
69
  cache_dir = ENV["OUT"] || Apipie.configuration.cache_dir
70
70
  subdir = Apipie.configuration.doc_base_url.sub(/\A\//,"")
71
+ subdir_levels = subdir.split('/').length
72
+ subdir_traversal_prefix = '../' * subdir_levels
71
73
  file_base = File.join(cache_dir, Apipie.configuration.doc_base_url)
72
74
 
73
75
  if generate_index
@@ -78,15 +80,15 @@ namespace :apipie do
78
80
  end
79
81
  Apipie.available_versions.each do |version|
80
82
  file_base_version = File.join(file_base, version)
81
- Apipie.url_prefix = "../#{subdir}"
83
+ Apipie.url_prefix = "#{subdir_traversal_prefix}#{subdir}"
82
84
  doc = Apipie.to_json(version, nil, nil, lang)
83
85
  doc[:docs][:link_extension] = (lang ? ".#{lang}.html" : ".html")
84
86
 
85
87
  generate_index_page(file_base_version, doc, true, true, lang) if generate_index
86
88
  if generate_resources
87
- Apipie.url_prefix = "../../#{subdir}"
89
+ Apipie.url_prefix = "../#{subdir_traversal_prefix}#{subdir}"
88
90
  generate_resource_pages(version, file_base_version, doc, true, lang)
89
- Apipie.url_prefix = "../../../#{subdir}"
91
+ Apipie.url_prefix = "../../#{subdir_traversal_prefix}#{subdir}"
90
92
  generate_method_pages(version, file_base_version, doc, true, lang)
91
93
  end
92
94
  end
@@ -30,6 +30,7 @@ describe UsersController do
30
30
  it "should contain all resource methods" do
31
31
  methods = subject._methods
32
32
  methods.keys.should include(:show)
33
+ methods.keys.should include(:create_route)
33
34
  methods.keys.should include(:index)
34
35
  methods.keys.should include(:create)
35
36
  methods.keys.should include(:update)
@@ -74,233 +75,287 @@ describe UsersController do
74
75
 
75
76
  end
76
77
 
77
- context "only presence validations are enabled" do
78
- before do
79
- Apipie.configuration.validate = true
80
- Apipie.configuration.validate_value = false
81
- Apipie.configuration.validate_presence = true
82
- end
83
-
84
- it "should reply to valid request" do
85
- lambda { get :show, :id => 5, :session => "secret_hash" }.should_not raise_error
86
- assert_response :success
78
+ context "validations are enabled" do
79
+ def reload_controllers
80
+ controllers_dirname = File.expand_path('../dummy/app/controllers', File.dirname(__FILE__))
81
+ Dir.glob("#{controllers_dirname}/**/*") { |file| load(file) if File.file?(file) }
87
82
  end
88
83
 
89
- it "should fail if required parameter is missing" do
90
- lambda { get :show, :id => 5 }.should raise_error(Apipie::ParamMissing, /\bsession\b/)
91
- end
84
+ shared_examples "validates correctly" do
92
85
 
93
- it "should pass if required parameter has wrong type" do
94
- lambda { get :show, :id => 5, :session => "secret_hash" }.should_not raise_error
95
- lambda { get :show, :id => "ten", :session => "secret_hash" }.should_not raise_error
96
- end
86
+ context "only presence validations are enabled" do
87
+ before do
88
+ Apipie.configuration.validate_value = false
89
+ Apipie.configuration.validate_presence = true
90
+ Apipie.configuration.validate_key = false
91
+ end
97
92
 
98
- end
93
+ it "should reply to valid request" do
94
+ lambda { get :show, :id => 5, :session => "secret_hash" }.should_not raise_error
95
+ assert_response :success
96
+ end
99
97
 
98
+ it "should fail if required parameter is missing" do
99
+ lambda { get :show, :id => 5 }.should raise_error(Apipie::ParamMissing, /\bsession\b/)
100
+ end
100
101
 
101
- context "validations are enabled" do
102
- before do
103
- Apipie.configuration.validate = true
104
- Apipie.configuration.validate_value = true
105
- Apipie.configuration.validate_presence = true
106
- end
102
+ it "should pass if required parameter has wrong type" do
103
+ lambda { get :show, :id => 5, :session => "secret_hash" }.should_not raise_error
104
+ lambda { get :show, :id => "ten", :session => "secret_hash" }.should_not raise_error
105
+ end
107
106
 
108
- it "should reply to valid request" do
109
- get :show, :id => '5', :session => "secret_hash"
110
- assert_response :success
111
- end
107
+ end
112
108
 
113
- it "should work with nil value for a required hash param" do
114
- expect {
115
- get :show, :id => '5', :session => "secret_hash", :hash_param => {:dummy_hash => nil}
116
- }.to raise_error(Apipie::ParamInvalid, /dummy_hash/)
117
- assert_response :success
118
- end
109
+ context "key validations are enabled" do
110
+ before do
111
+ Apipie.configuration.validate_value = false
112
+ Apipie.configuration.validate_presence = true
113
+ Apipie.configuration.validate_key = true
114
+ end
119
115
 
120
- it "should fail if required parameter is missing" do
121
- lambda { get :show, :id => 5 }.should raise_error(Apipie::ParamMissing, /\bsession\b/)
122
- end
116
+ it "should reply to valid request" do
117
+ lambda { get :show, :id => 5, :session => "secret_hash" }.should_not raise_error
118
+ assert_response :success
119
+ end
123
120
 
124
- it "should work with custom Type validator" do
125
- lambda {
126
- get :show,
127
- :id => "not a number",
128
- :session => "secret_hash"
129
- }.should raise_error(Apipie::ParamError, /id/) # old-style error rather than ParamInvalid
130
- end
121
+ it "should fail if extra parameter is passed in" do
122
+ lambda { get :show, :id => 5, :session => "secret_hash", :badparam => 'badfoo' }.should raise_error(Apipie::UnknownParam, /\bbadparam\b/)
123
+ end
124
+ end
131
125
 
132
- it "should work with Regexp validator" do
133
- get :show,
134
- :id => 5,
135
- :session => "secret_hash",
136
- :regexp_param => "24 years"
137
- assert_response :success
126
+ context "presence and value validations are enabled" do
127
+ before do
128
+ Apipie.configuration.validate_value = true
129
+ Apipie.configuration.validate_presence = true
130
+ Apipie.configuration.validate_key = false
131
+ end
138
132
 
139
- lambda {
140
- get :show,
141
- :id => 5,
142
- :session => "secret_hash",
143
- :regexp_param => "ten years"
144
- }.should raise_error(Apipie::ParamInvalid, /regexp_param/)
145
- end
133
+ it "should reply to valid request" do
134
+ get :show, :id => '5', :session => "secret_hash"
135
+ assert_response :success
136
+ end
146
137
 
147
- it "should work with Array validator" do
148
- get :show, :id => 5, :session => "secret_hash", :array_param => "one"
149
- assert_response :success
150
- get :show, :id => 5, :session => "secret_hash", :array_param => "two"
151
- assert_response :success
152
- get :show, :id => 5, :session => "secret_hash", :array_param => '1'
153
- assert_response :success
154
- get :show, :id => 5, :session => "secret_hash", :boolean_param => false
155
- assert_response :success
138
+ it "should work with nil value for a required hash param" do
139
+ expect {
140
+ get :show, :id => '5', :session => "secret_hash", :hash_param => {:dummy_hash => nil}
141
+ }.to raise_error(Apipie::ParamInvalid, /dummy_hash/)
142
+ assert_response :success
143
+ end
156
144
 
157
- lambda {
158
- get :show,
159
- :id => 5,
160
- :session => "secret_hash",
161
- :array_param => "blabla"
162
- }.should raise_error(Apipie::ParamInvalid, /array_param/)
163
-
164
- lambda {
165
- get :show,
166
- :id => 5,
167
- :session => "secret_hash",
168
- :array_param => 3
169
- }.should raise_error(Apipie::ParamInvalid, /array_param/)
170
- end
145
+ it "should fail if required parameter is missing" do
146
+ lambda { get :show, :id => 5 }.should raise_error(Apipie::ParamMissing, /\bsession\b/)
147
+ end
171
148
 
172
- it "should work with Proc validator" do
173
- lambda {
174
- get :show,
175
- :id => 5,
176
- :session => "secret_hash",
177
- :proc_param => "asdgsag"
178
- }.should raise_error(Apipie::ParamInvalid, /proc_param/)
179
-
180
- get :show,
181
- :id => 5,
182
- :session => "secret_hash",
183
- :proc_param => "param value"
184
- assert_response :success
185
- end
149
+ it "should work with custom Type validator" do
150
+ lambda {
151
+ get :show,
152
+ :id => "not a number",
153
+ :session => "secret_hash"
154
+ }.should raise_error(Apipie::ParamError, /id/) # old-style error rather than ParamInvalid
155
+ end
186
156
 
187
- it "should work with Hash validator" do
188
- post :create, :user => { :name => "root", :pass => "12345", :membership => "standard" }
189
- assert_response :success
157
+ it "should work with Regexp validator" do
158
+ get :show,
159
+ :id => 5,
160
+ :session => "secret_hash",
161
+ :regexp_param => "24 years"
162
+ assert_response :success
190
163
 
191
- a = Apipie[UsersController, :create]
192
- param = a.params_ordered.select {|p| p.name == :user }
193
- param.count.should == 1
194
- param.first.validator.class.should eq(Apipie::Validator::HashValidator)
195
- hash_params = param.first.validator.params_ordered
196
- hash_params.count.should == 4
197
- hash_params[0].name == :name
198
- hash_params[1].name == :pass
199
- hash_params[2].name == :membership
200
-
201
- lambda {
202
- post :create, :user => { :name => "root", :pass => "12345", :membership => "____" }
203
- }.should raise_error(Apipie::ParamInvalid, /membership/)
204
-
205
- lambda {
206
- post :create, :user => { :name => "root" }
207
- }.should raise_error(Apipie::ParamMissing, /pass/)
208
-
209
- lambda {
210
- post :create, :user => "a string is not a hash"
211
- }.should raise_error(Apipie::ParamInvalid, /user/)
212
-
213
- post :create, :user => { :name => "root", :pass => "pwd" }
214
- assert_response :success
215
- end
164
+ lambda {
165
+ get :show,
166
+ :id => 5,
167
+ :session => "secret_hash",
168
+ :regexp_param => "ten years"
169
+ }.should raise_error(Apipie::ParamInvalid, /regexp_param/)
170
+ end
216
171
 
217
- it "should support Hash validator without specifying keys" do
218
- params = Apipie[UsersController, :create].to_json[:params]
219
- params.should include(:name => "facts",
220
- :full_name => "facts",
221
- :validator => "Must be Hash",
222
- :description => "\n<p>Additional optional facts about the user</p>\n",
223
- :required => false,
224
- :allow_nil => true,
225
- :metadata => nil,
226
- :show => true,
227
- :expected_type => "hash")
228
- end
172
+ it "should work with Array validator" do
173
+ get :show, :id => 5, :session => "secret_hash", :array_param => "one"
174
+ assert_response :success
175
+ get :show, :id => 5, :session => "secret_hash", :array_param => "two"
176
+ assert_response :success
177
+ get :show, :id => 5, :session => "secret_hash", :array_param => '1'
178
+ assert_response :success
179
+ get :show, :id => 5, :session => "secret_hash", :boolean_param => false
180
+ assert_response :success
229
181
 
230
- it "should allow nil when allow_nil is set to true" do
231
- post :create,
232
- :user => {
233
- :name => "root",
234
- :pass => "12345",
235
- :membership => "standard",
236
- },
237
- :facts => nil
238
- assert_response :success
239
- end
182
+ lambda {
183
+ get :show,
184
+ :id => 5,
185
+ :session => "secret_hash",
186
+ :array_param => "blabla"
187
+ }.should raise_error(Apipie::ParamInvalid, /array_param/)
240
188
 
241
- describe "nested elements" do
189
+ lambda {
190
+ get :show,
191
+ :id => 5,
192
+ :session => "secret_hash",
193
+ :array_param => 3
194
+ }.should raise_error(Apipie::ParamInvalid, /array_param/)
195
+ end
242
196
 
243
- context "with valid input" do
244
- it "should succeed" do
245
- put :update,
246
- {
197
+ it "should work with Proc validator" do
198
+ lambda {
199
+ get :show,
247
200
  :id => 5,
248
- :user => {
249
- :name => "root",
250
- :pass => "12345"
251
- },
252
- :comments => [
253
- {
254
- :comment => 'comment1'
255
- },
256
- {
257
- :comment => 'comment2'
258
- }
259
- ]
260
- }
201
+ :session => "secret_hash",
202
+ :proc_param => "asdgsag"
203
+ }.should raise_error(Apipie::ParamInvalid, /proc_param/)
261
204
 
205
+ get :show,
206
+ :id => 5,
207
+ :session => "secret_hash",
208
+ :proc_param => "param value"
262
209
  assert_response :success
263
210
  end
264
- end
265
- context "with bad input" do
266
- it "should raise an error" do
267
- expect{
268
- put :update,
269
- {
270
- :id => 5,
271
- :user => {
272
- :name => "root",
273
- :pass => "12345"
274
- },
275
- :comments => [
211
+
212
+ it "should work with Hash validator" do
213
+ post :create, :user => { :name => "root", :pass => "12345", :membership => "standard" }
214
+ assert_response :success
215
+
216
+ a = Apipie[UsersController, :create]
217
+ param = a.params_ordered.select {|p| p.name == :user }
218
+ param.count.should == 1
219
+ param.first.validator.class.should eq(Apipie::Validator::HashValidator)
220
+ hash_params = param.first.validator.params_ordered
221
+ hash_params.count.should == 4
222
+ hash_params[0].name == :name
223
+ hash_params[1].name == :pass
224
+ hash_params[2].name == :membership
225
+
226
+ lambda {
227
+ post :create, :user => { :name => "root", :pass => "12345", :membership => "____" }
228
+ }.should raise_error(Apipie::ParamInvalid, /membership/)
229
+
230
+ lambda {
231
+ post :create, :user => { :name => "root" }
232
+ }.should raise_error(Apipie::ParamMissing, /pass/)
233
+
234
+ lambda {
235
+ post :create, :user => "a string is not a hash"
236
+ }.should raise_error(Apipie::ParamInvalid, /user/)
237
+
238
+ post :create, :user => { :name => "root", :pass => "pwd" }
239
+ assert_response :success
240
+ end
241
+
242
+ it "should support Hash validator without specifying keys" do
243
+ params = Apipie[UsersController, :create].to_json[:params]
244
+ params.should include(:name => "facts",
245
+ :full_name => "facts",
246
+ :validator => "Must be Hash",
247
+ :description => "\n<p>Additional optional facts about the user</p>\n",
248
+ :required => false,
249
+ :allow_nil => true,
250
+ :metadata => nil,
251
+ :show => true,
252
+ :expected_type => "hash")
253
+ end
254
+
255
+ it "should allow nil when allow_nil is set to true" do
256
+ post :create,
257
+ :user => {
258
+ :name => "root",
259
+ :pass => "12345",
260
+ :membership => "standard",
261
+ },
262
+ :facts => nil
263
+ assert_response :success
264
+ end
265
+
266
+ describe "nested elements" do
267
+
268
+ context "with valid input" do
269
+ it "should succeed" do
270
+ put :update,
276
271
  {
277
- :comment => 'comment1'
278
- },
272
+ :id => 5,
273
+ :user => {
274
+ :name => "root",
275
+ :pass => "12345"
276
+ },
277
+ :comments => [
278
+ {
279
+ :comment => 'comment1'
280
+ },
281
+ {
282
+ :comment => 'comment2'
283
+ }
284
+ ]
285
+ }
286
+
287
+ assert_response :success
288
+ end
289
+ end
290
+ context "with bad input" do
291
+ it "should raise an error" do
292
+ expect{
293
+ put :update,
279
294
  {
280
- :comment => {:bad_input => 5}
295
+ :id => 5,
296
+ :user => {
297
+ :name => "root",
298
+ :pass => "12345"
299
+ },
300
+ :comments => [
301
+ {
302
+ :comment => 'comment1'
303
+ },
304
+ {
305
+ :comment => {:bad_input => 5}
306
+ }
307
+ ]
281
308
  }
282
- ]
283
- }
284
- }.to raise_error(Apipie::ParamInvalid)
309
+ }.to raise_error(Apipie::ParamInvalid)
310
+ end
311
+ end
312
+ it "should work with empty array" do
313
+ put :update,
314
+ {
315
+ :id => 5,
316
+ :user => {
317
+ :name => "root",
318
+ :pass => "12345"
319
+ },
320
+ :comments => [
321
+ ]
322
+ }
323
+
324
+ assert_response :success
325
+ end
285
326
  end
327
+
286
328
  end
287
- it "should work with empty array" do
288
- put :update,
289
- {
290
- :id => 5,
291
- :user => {
292
- :name => "root",
293
- :pass => "12345"
294
- },
295
- :comments => [
296
- ]
297
- }
298
-
299
- assert_response :success
329
+ end
330
+
331
+ context "using configuration.validate = true" do
332
+ before :all do
333
+ Apipie.configuration.validate = true
334
+ reload_controllers
300
335
  end
336
+
337
+ it_behaves_like "validates correctly"
301
338
  end
302
339
 
340
+ context "using configuration.validate = :implicitly" do
341
+ before :all do
342
+ Apipie.configuration.validate = :implicitly
343
+ reload_controllers
344
+ end
345
+
346
+ it_behaves_like "validates correctly"
347
+ end
348
+
349
+ context "using configuration.validate = :explicitly" do
350
+ before :all do
351
+ Apipie.configuration.validate = :explicitly
352
+ reload_controllers
353
+ end
354
+
355
+ it_behaves_like "validates correctly"
356
+ end
303
357
  end
358
+
304
359
  end
305
360
 
306
361
  describe "method description" do
@@ -328,6 +383,19 @@ describe UsersController do
328
383
  b.full_description.length.should be > 400
329
384
  end
330
385
 
386
+ context "Usign routes.rb" do
387
+ it "should contain basic info about method" do
388
+ a = Apipie[UsersController, :create_route]
389
+ a.apis.count.should == 1
390
+ a.formats.should eq(['json'])
391
+ api = a.apis.first
392
+ api.short_description.should eq("Create user")
393
+ api.path.should eq("/api/users/create_route")
394
+ api.from_routes.should be_true
395
+ api.http_method.should eq("POST")
396
+ end
397
+ end
398
+
331
399
  context "contain :see option" do
332
400
 
333
401
  context "the key is valid" do