apipie-rails 0.2.6 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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