apipie-rails 0.3.6 → 0.5.17

Sign up to get free protection for your applications and to get access to all the features.
Files changed (91) hide show
  1. checksums.yaml +5 -5
  2. data/.travis.yml +23 -7
  3. data/CHANGELOG.md +147 -2
  4. data/Gemfile +1 -0
  5. data/Gemfile.rails41 +2 -0
  6. data/Gemfile.rails42 +10 -1
  7. data/Gemfile.rails50 +9 -0
  8. data/Gemfile.rails51 +9 -0
  9. data/Gemfile.rails60 +14 -0
  10. data/PROPOSAL_FOR_RESPONSE_DESCRIPTIONS.md +244 -0
  11. data/README.rst +570 -17
  12. data/apipie-rails.gemspec +3 -3
  13. data/app/controllers/apipie/apipies_controller.rb +48 -17
  14. data/app/views/apipie/apipies/_method_detail.erb +21 -0
  15. data/app/views/apipie/apipies/_params.html.erb +4 -2
  16. data/app/views/apipie/apipies/index.html.erb +5 -1
  17. data/app/views/apipie/apipies/resource.html.erb +3 -0
  18. data/app/views/layouts/apipie/apipie.html.erb +1 -1
  19. data/config/locales/en.yml +1 -0
  20. data/config/locales/fr.yml +31 -0
  21. data/config/locales/it.yml +31 -0
  22. data/config/locales/ja.yml +31 -0
  23. data/lib/apipie/apipie_module.rb +22 -4
  24. data/lib/apipie/application.rb +55 -28
  25. data/lib/apipie/configuration.rb +19 -3
  26. data/lib/apipie/core_ext/route.rb +9 -0
  27. data/lib/apipie/dsl_definition.rb +151 -10
  28. data/lib/apipie/error_description.rb +9 -2
  29. data/lib/apipie/errors.rb +34 -0
  30. data/lib/apipie/extractor/collector.rb +4 -0
  31. data/lib/apipie/extractor/recorder.rb +13 -12
  32. data/lib/apipie/extractor/writer.rb +83 -55
  33. data/lib/apipie/extractor.rb +10 -4
  34. data/lib/apipie/method_description.rb +51 -4
  35. data/lib/apipie/param_description.rb +56 -2
  36. data/lib/apipie/resource_description.rb +10 -3
  37. data/lib/apipie/response_description.rb +131 -0
  38. data/lib/apipie/response_description_adapter.rb +200 -0
  39. data/lib/apipie/routes_formatter.rb +1 -1
  40. data/lib/apipie/rspec/response_validation_helper.rb +194 -0
  41. data/lib/apipie/static_dispatcher.rb +3 -2
  42. data/lib/apipie/swagger_generator.rb +708 -0
  43. data/lib/apipie/tag_list_description.rb +11 -0
  44. data/lib/apipie/validator.rb +69 -8
  45. data/lib/apipie/version.rb +1 -1
  46. data/lib/apipie-rails.rb +7 -0
  47. data/lib/tasks/apipie.rake +103 -8
  48. data/spec/controllers/apipies_controller_spec.rb +52 -12
  49. data/spec/controllers/concerns_controller_spec.rb +2 -2
  50. data/spec/controllers/extended_controller_spec.rb +14 -0
  51. data/spec/controllers/memes_controller_spec.rb +10 -0
  52. data/spec/controllers/users_controller_spec.rb +115 -75
  53. data/spec/dummy/app/controllers/application_controller.rb +5 -1
  54. data/spec/dummy/app/controllers/concerns/extending_concern.rb +12 -0
  55. data/spec/dummy/app/controllers/concerns/sample_controller.rb +5 -5
  56. data/spec/dummy/app/controllers/extended_controller.rb +14 -0
  57. data/spec/dummy/app/controllers/pets_controller.rb +408 -0
  58. data/spec/dummy/app/controllers/pets_using_auto_views_controller.rb +73 -0
  59. data/spec/dummy/app/controllers/pets_using_self_describing_classes_controller.rb +95 -0
  60. data/spec/dummy/app/controllers/tagged_cats_controller.rb +32 -0
  61. data/spec/dummy/app/controllers/tagged_dogs_controller.rb +15 -0
  62. data/spec/dummy/app/controllers/twitter_example_controller.rb +5 -0
  63. data/spec/dummy/app/controllers/users_controller.rb +19 -11
  64. data/spec/dummy/components/test_engine/Gemfile +6 -0
  65. data/spec/dummy/components/test_engine/app/controllers/test_engine/application_controller.rb +4 -0
  66. data/spec/dummy/components/test_engine/app/controllers/test_engine/memes_controller.rb +37 -0
  67. data/spec/dummy/components/test_engine/config/routes.rb +3 -0
  68. data/spec/dummy/components/test_engine/db/.gitkeep +0 -0
  69. data/spec/dummy/components/test_engine/lib/test_engine.rb +7 -0
  70. data/spec/dummy/components/test_engine/test_engine.gemspec +11 -0
  71. data/spec/dummy/config/application.rb +5 -0
  72. data/spec/dummy/config/environments/development.rb +3 -0
  73. data/spec/dummy/config/environments/production.rb +3 -0
  74. data/spec/dummy/config/environments/test.rb +3 -0
  75. data/spec/dummy/config/initializers/apipie.rb +3 -1
  76. data/spec/dummy/config/routes.rb +24 -1
  77. data/spec/lib/extractor/writer_spec.rb +32 -4
  78. data/spec/lib/file_handler_spec.rb +18 -0
  79. data/spec/lib/method_description_spec.rb +34 -0
  80. data/spec/lib/swagger/openapi_2_0_schema.json +1607 -0
  81. data/spec/lib/swagger/rake_swagger_spec.rb +139 -0
  82. data/spec/lib/swagger/response_validation_spec.rb +104 -0
  83. data/spec/lib/swagger/swagger_dsl_spec.rb +658 -0
  84. data/spec/lib/validator_spec.rb +58 -0
  85. data/spec/lib/validators/array_validator_spec.rb +28 -8
  86. data/spec/spec_helper.rb +68 -0
  87. metadata +75 -23
  88. data/Gemfile +0 -7
  89. data/Gemfile.rails32 +0 -6
  90. data/Gemfile.rails40 +0 -5
  91. data/lib/apipie/client/generator.rb +0 -135
@@ -192,15 +192,15 @@ class UsersController < ApplicationController
192
192
  end
193
193
  def show
194
194
  unless params[:session] == "secret_hash"
195
- render :text => "Not authorized", :status => 401
195
+ render :plain => "Not authorized", :status => 401
196
196
  return
197
197
  end
198
198
 
199
199
  unless params[:id].to_i == 5
200
- render :text => "Not Found", :status => 404 and return
200
+ render :plain => "Not Found", :status => 404 and return
201
201
  end
202
202
 
203
- render :text => "OK"
203
+ render :plain => "OK"
204
204
  end
205
205
 
206
206
  def_param_group :credentials do
@@ -221,8 +221,10 @@ class UsersController < ApplicationController
221
221
  param :permalink, String
222
222
  end
223
223
  param :facts, Hash, :desc => "Additional optional facts about the user", :allow_nil => true
224
+ param :age, :number, :desc => "Age is just a number", :allow_blank => true
225
+ error :unprocessable_entity, 'Unprocessable Entity'
224
226
  def create
225
- render :text => "OK #{params.inspect}"
227
+ render :plain => "OK #{params.inspect}"
226
228
  end
227
229
 
228
230
  api :PUT, "/users/:id", "Update an user"
@@ -231,13 +233,13 @@ class UsersController < ApplicationController
231
233
  param :comment, String
232
234
  end
233
235
  def update
234
- render :text => "OK #{params.inspect}"
236
+ render :plain => "OK #{params.inspect}"
235
237
  end
236
238
 
237
239
  api :POST, "/users/admin", "Create admin user"
238
240
  param_group :user, :as => :create
239
241
  def admin_create
240
- render :text => "OK #{params.inspect}"
242
+ render :plain => "OK #{params.inspect}"
241
243
  end
242
244
 
243
245
  api :GET, "/users", "List users"
@@ -247,14 +249,14 @@ class UsersController < ApplicationController
247
249
  param :oauth, nil,
248
250
  :desc => "Hide this global param (eg dont need auth here)"
249
251
  def index
250
- render :text => "List of users"
252
+ render :plain => "List of users"
251
253
  end
252
254
 
253
255
  api :GET, '/company_users', 'Get company users'
254
256
  api :GET, '/company/:id/users', 'Get users working in given company'
255
257
  param :id, Integer, :desc => "Company ID"
256
258
  def two_urls
257
- render :text => 'List of users'
259
+ render :plain => 'List of users'
258
260
  end
259
261
 
260
262
  api :GET, '/users/see_another', 'Boring method'
@@ -263,14 +265,19 @@ class UsersController < ApplicationController
263
265
  see 'development#users#index', "very interesting method reference"
264
266
  desc 'This method is boring, look at users#create. It is hidden from documentation.'
265
267
  def see_another
266
- render :text => 'This is very similar to create action'
268
+ render :plain => 'This is very similar to create action'
267
269
  end
268
270
 
271
+ api :GET, '/users/by_department', 'show users from a specific department'
272
+ param :department, ["finance", "operations", "sales", "marketing", "HR"], required: false, default_value: "sales"
273
+ def get_by_department
274
+ render :plain => 'nothing to see here'
275
+ end
269
276
 
270
277
  api :GET, '/users/desc_from_file', 'desc from file'
271
278
  document 'users/desc_from_file.md'
272
279
  def desc_from_file
273
- render :text => 'document from file action'
280
+ render :plain => 'document from file action'
274
281
  end
275
282
 
276
283
  api! 'Create user'
@@ -284,7 +291,8 @@ class UsersController < ApplicationController
284
291
 
285
292
  api :GET, '/users/action_with_headers'
286
293
  header :RequredHeaderName, 'Required header description', required: true
287
- header :OptionalHeaderName, 'Optional header description', required: false
294
+ header :OptionalHeaderName, 'Optional header description', required: false, type: 'string'
295
+ header :HeaderNameWithDefaultValue, 'Header with default value', required: true, default: 'default value'
288
296
  def action_with_headers
289
297
  end
290
298
  end
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Declare your gem's dependencies in test_engine.gemspec.
4
+ # Bundler will treat runtime dependencies like base dependencies, and
5
+ # development dependencies will be added by default to the :development group.
6
+ gemspec
@@ -0,0 +1,4 @@
1
+ module TestEngine
2
+ class ApplicationController < ActionController::Base
3
+ end
4
+ end
@@ -0,0 +1,37 @@
1
+ module TestEngine
2
+ class MemesController < TestEngine::ApplicationController
3
+ api! 'Returns a list of all good memes on Twitter'
4
+ param :api_token, String, required: true, desc: 'Your Twitter API token'
5
+ def index
6
+ render json: []
7
+ end
8
+
9
+ api! 'Shows info about a particular meme on Twitter'
10
+ param :id, :number, required: true, desc: 'ID of the meme'
11
+ def show
12
+ render json: {id: params[:id]}
13
+ end
14
+
15
+ api! 'Create a new meme on Twitter'
16
+ param :api_token, String, required: true, desc: 'Your Twitter API token'
17
+ param :name, String, required: true, desc: 'Name of your meme'
18
+ param :src_url, String, required: true, desc: 'URL for your meme'
19
+ def create
20
+ render json: {name: params[:name], src_url: params[:src_url]}, status: :created
21
+ end
22
+
23
+ api! 'Update a meme on Twitter'
24
+ param :api_token, String, required: true, desc: 'Your Twitter API token'
25
+ param :name, String, required: false, desc: 'Name of your meme'
26
+ param :src_url, String, required: false, desc: 'URL for your meme'
27
+ def update
28
+ render json: {name: params[:name], src_url: params[:src_url]}
29
+ end
30
+
31
+ api! 'Delete a meme on Twitter'
32
+ param :id, :number, required: true, desc: 'ID of the meme'
33
+ def destroy
34
+ head :ok
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,3 @@
1
+ TestEngine::Engine.routes.draw do
2
+ resources :memes, only: [:index, :show, :create, :update, :destroy]
3
+ end
File without changes
@@ -0,0 +1,7 @@
1
+ require 'apipie-rails'
2
+
3
+ module TestEngine
4
+ class Engine < ::Rails::Engine
5
+ isolate_namespace TestEngine
6
+ end
7
+ end
@@ -0,0 +1,11 @@
1
+ $:.push File.expand_path('../lib', __FILE__)
2
+
3
+ # Describe your gem and declare its dependencies:
4
+ Gem::Specification.new do |s|
5
+ s.name = 'test_engine'
6
+ s.version = '0.0.1'
7
+ s.summary = 'Test Engine'
8
+ s.authors = 'Test Author'
9
+
10
+ s.files = Dir['{app,config,db,lib}/**/*']
11
+ end
@@ -8,6 +8,7 @@ require "action_mailer/railtie"
8
8
 
9
9
  Bundler.require
10
10
  require "apipie-rails"
11
+ require "test_engine"
11
12
 
12
13
  module Dummy
13
14
  class Application < Rails::Application
@@ -41,5 +42,9 @@ module Dummy
41
42
 
42
43
  # Configure sensitive parameters which will be filtered from the log file.
43
44
  config.filter_parameters += [:password]
45
+
46
+ config.to_prepare do
47
+ ExtendedController.send(:include, Concerns::ExtendingConcern)
48
+ end
44
49
  end
45
50
  end
@@ -21,5 +21,8 @@ Dummy::Application.configure do
21
21
 
22
22
  # Only use best-standards-support built into browsers
23
23
  config.action_dispatch.best_standards_support = :builtin
24
+
25
+ # Do not eager load code on boot. (Rails 5)
26
+ config.eager_load = false
24
27
  end
25
28
 
@@ -46,4 +46,7 @@ Dummy::Application.configure do
46
46
 
47
47
  # Send deprecation notices to registered listeners
48
48
  config.active_support.deprecation = :notify
49
+
50
+ # Eager load code on boot (Rails 5)
51
+ config.eager_load = true
49
52
  end
@@ -32,4 +32,7 @@ Dummy::Application.configure do
32
32
 
33
33
  # Print deprecation notices to the stderr
34
34
  config.active_support.deprecation = :stderr
35
+
36
+ # Do not eager load code on boot. (Rails 5)
37
+ config.eager_load = false
35
38
  end
@@ -1,12 +1,14 @@
1
1
  Apipie.configure do |config|
2
2
  config.app_name = "Test app"
3
3
  config.copyright = "&copy; 2012 Pavel Pokorny"
4
+ config.languages = ['en']
5
+ config.default_locale = 'en'
4
6
 
5
7
  # set default API version
6
8
  # can be overriden in resource_description
7
9
  # by default is it 1.0 if not specified anywhere
8
10
  # this must be defined before api_base_url and app_info
9
- config.default_version = "development"
11
+ config.default_version = "development".freeze
10
12
 
11
13
  config.doc_base_url = "/apidoc"
12
14
 
@@ -1,5 +1,7 @@
1
1
  Dummy::Application.routes.draw do
2
2
 
3
+ mount TestEngine::Engine => '/test'
4
+
3
5
  scope ENV['RAILS_RELATIVE_URL_ROOT'] || '/' do
4
6
 
5
7
  scope '/api' do
@@ -10,8 +12,13 @@ Dummy::Application.routes.draw do
10
12
  end
11
13
  resources :concerns, :only => [:index, :show]
12
14
  namespace :files do
13
- get '/*file_path', to: :download, format: false
15
+ get '/*file_path', format: false, :action => 'download'
14
16
  end
17
+
18
+ # This is not directly used in the specs.
19
+ # It is only there to tests apipies tolerance regarding
20
+ # missing controllers.
21
+ resources :dangeling_stuff
15
22
  resources :twitter_example do
16
23
  collection do
17
24
  get :lookup
@@ -21,6 +28,22 @@ Dummy::Application.routes.draw do
21
28
  get :contributors
22
29
  end
23
30
  end
31
+
32
+ get "/pets/return_and_validate_expected_response" => "pets#return_and_validate_expected_response"
33
+ get "/pets/return_and_validate_expected_array_response" => "pets#return_and_validate_expected_array_response"
34
+ get "/pets/return_and_validate_type_mismatch" => "pets#return_and_validate_type_mismatch"
35
+ get "/pets/return_and_validate_missing_field" => "pets#return_and_validate_missing_field"
36
+ get "/pets/return_and_validate_extra_property" => "pets#return_and_validate_extra_property"
37
+ get "/pets/return_and_validate_allowed_extra_property" => "pets#return_and_validate_allowed_extra_property"
38
+ get "/pets/sub_object_invalid_extra_property" => "pets#sub_object_invalid_extra_property"
39
+ get "/pets/sub_object_allowed_extra_property" => "pets#sub_object_allowed_extra_property"
40
+ get "/pets/return_and_validate_unexpected_array_response" => "pets#return_and_validate_unexpected_array_response"
41
+ get "/pets/return_and_validate_expected_response_with_null" => "pets#return_and_validate_expected_response_with_null"
42
+ get "/pets/return_and_validate_expected_response_with_null_object" => "pets#return_and_validate_expected_response_with_null_object"
43
+
44
+ get "/pets/returns_response_with_valid_array" => "pets#returns_response_with_valid_array"
45
+ get "/pets/returns_response_with_invalid_array" => "pets#returns_response_with_invalid_array"
46
+ get "/pets/undocumented_method" => "pets#undocumented_method"
24
47
  end
25
48
 
26
49
  apipie
@@ -57,10 +57,38 @@ describe Apipie::Extractor::Writer do
57
57
  }
58
58
  }
59
59
 
60
- describe "with doc_path overriden in configuration" do
61
- it "should use the doc_path specified in configuration" do
62
- Apipie.configuration.doc_path = "user_specified_doc_path"
63
- expect(writer_class.examples_file).to eql(File.join(Rails.root, "user_specified_doc_path", "apipie_examples.json"))
60
+ context 'with doc_path overriden in configuration' do
61
+ around(:each) do |example|
62
+ standard_path = Apipie.configuration.doc_path
63
+ Apipie.configuration.doc_path = 'user_specified_doc_path'
64
+ example.run
65
+ Apipie.configuration.doc_path = standard_path
66
+ end
67
+
68
+ it 'should use the doc_path specified in configuration' do
69
+ expect(writer_class.examples_file).to eql(File.join(Rails.root, 'user_specified_doc_path', 'apipie_examples.json'))
70
+ end
71
+ end
72
+
73
+ context 'when compressing examples' do
74
+ around(:each) do |example|
75
+ Apipie.configuration.compress_examples = true
76
+ example.run
77
+ FileUtils.rm(writer_class.examples_file) if File.exist?(writer_class.examples_file)
78
+ Apipie.configuration.compress_examples = nil
79
+ end
80
+
81
+ it 'should write to a compressed file' do
82
+ expect(writer_class.examples_file).to match(/\.gz$/)
83
+ writer_class.write_recorded_examples(records)
84
+ expect(File.exist?(writer_class.examples_file))
85
+ end
86
+
87
+ it 'should read from a compressed file' do
88
+ writer_class.write_recorded_examples(records)
89
+ expected_string = writer_class.send(:serialize_examples, records)
90
+ expect(writer_class.load_recorded_examples)
91
+ .to eql(writer_class.send(:deserialize_examples, expected_string))
64
92
  end
65
93
  end
66
94
 
@@ -0,0 +1,18 @@
1
+ require "spec_helper"
2
+
3
+ describe Apipie::FileHandler do
4
+
5
+ describe "match?" do
6
+ let(:file_handler) { Apipie::FileHandler.new File.dirname(__FILE__) }
7
+
8
+ it { expect(file_handler.match? 'file_handler_spec.rb').to be_truthy }
9
+ it { expect(file_handler.match? 'foo.bar').to be_falsy }
10
+
11
+ context 'path contains null bytes' do
12
+ let(:path) { "foo%00.bar" }
13
+
14
+ it { expect(file_handler.match? path).to be_falsy }
15
+ it { expect { file_handler.match? path }.to_not raise_error }
16
+ end
17
+ end
18
+ end
@@ -36,6 +36,13 @@ describe Apipie::MethodDescription do
36
36
  method = Apipie::MethodDescription.new(:a, @resource, dsl_data)
37
37
  expect(method.method_apis_to_json.first[:deprecated]).to eq(true)
38
38
  end
39
+
40
+ it "should return the deprecated flag if resource is deprecated" do
41
+ @resource.instance_variable_set("@_deprecated", true)
42
+ dsl_data[:api_args] = [[:GET, "/foo/bar", "description", {}]]
43
+ method = Apipie::MethodDescription.new(:a, @resource, dsl_data)
44
+ expect(method.method_apis_to_json.first[:deprecated]).to eq(true)
45
+ end
39
46
  end
40
47
 
41
48
  describe "params descriptions" do
@@ -61,4 +68,31 @@ describe Apipie::MethodDescription do
61
68
 
62
69
  end
63
70
 
71
+ describe "response-only properties" do
72
+ before(:each) do
73
+ @resource = Apipie::ResourceDescription.new(ApplicationController, "dummy")
74
+ dsl_data[:params] = [[:a, String, nil, {:only_in => :request}, nil],
75
+ [:b, String, nil, {:only_in => :response}, nil],
76
+ [:c, String, nil, {}, nil]]
77
+ @method = Apipie::MethodDescription.new(:a, @resource, dsl_data)
78
+ @resource.add_method_description @method
79
+ end
80
+
81
+ it "should ignore response-only parameters" do
82
+ expect(@method.params.keys).to eq([:a, :c])
83
+ expect(@method.to_json[:params].map{|h| h[:name]}).to eq(['a', 'c'])
84
+ end
85
+ end
86
+
87
+
88
+ describe "'returns' properties" do
89
+ it "should raise an error if both :param_group and :array_of are specified in 'returns'" do
90
+ @resource = Apipie::ResourceDescription.new(ApplicationController, "dummy")
91
+ dsl_data[:returns] = { 200 => [{:param_group => 'pet', :array_of => 'pet'}, nil, nil] }
92
+
93
+ expect {Apipie::MethodDescription.new(:a, @resource, dsl_data)}.to raise_error(Apipie::ReturnsMultipleDefinitionError)
94
+ end
95
+ end
96
+
97
+
64
98
  end