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.
- checksums.yaml +5 -5
- data/.travis.yml +23 -7
- data/CHANGELOG.md +147 -2
- data/Gemfile +1 -0
- data/Gemfile.rails41 +2 -0
- data/Gemfile.rails42 +10 -1
- data/Gemfile.rails50 +9 -0
- data/Gemfile.rails51 +9 -0
- data/Gemfile.rails60 +14 -0
- data/PROPOSAL_FOR_RESPONSE_DESCRIPTIONS.md +244 -0
- data/README.rst +570 -17
- data/apipie-rails.gemspec +3 -3
- data/app/controllers/apipie/apipies_controller.rb +48 -17
- data/app/views/apipie/apipies/_method_detail.erb +21 -0
- data/app/views/apipie/apipies/_params.html.erb +4 -2
- data/app/views/apipie/apipies/index.html.erb +5 -1
- data/app/views/apipie/apipies/resource.html.erb +3 -0
- data/app/views/layouts/apipie/apipie.html.erb +1 -1
- data/config/locales/en.yml +1 -0
- data/config/locales/fr.yml +31 -0
- data/config/locales/it.yml +31 -0
- data/config/locales/ja.yml +31 -0
- data/lib/apipie/apipie_module.rb +22 -4
- data/lib/apipie/application.rb +55 -28
- data/lib/apipie/configuration.rb +19 -3
- data/lib/apipie/core_ext/route.rb +9 -0
- data/lib/apipie/dsl_definition.rb +151 -10
- data/lib/apipie/error_description.rb +9 -2
- data/lib/apipie/errors.rb +34 -0
- data/lib/apipie/extractor/collector.rb +4 -0
- data/lib/apipie/extractor/recorder.rb +13 -12
- data/lib/apipie/extractor/writer.rb +83 -55
- data/lib/apipie/extractor.rb +10 -4
- data/lib/apipie/method_description.rb +51 -4
- data/lib/apipie/param_description.rb +56 -2
- data/lib/apipie/resource_description.rb +10 -3
- data/lib/apipie/response_description.rb +131 -0
- data/lib/apipie/response_description_adapter.rb +200 -0
- data/lib/apipie/routes_formatter.rb +1 -1
- data/lib/apipie/rspec/response_validation_helper.rb +194 -0
- data/lib/apipie/static_dispatcher.rb +3 -2
- data/lib/apipie/swagger_generator.rb +708 -0
- data/lib/apipie/tag_list_description.rb +11 -0
- data/lib/apipie/validator.rb +69 -8
- data/lib/apipie/version.rb +1 -1
- data/lib/apipie-rails.rb +7 -0
- data/lib/tasks/apipie.rake +103 -8
- data/spec/controllers/apipies_controller_spec.rb +52 -12
- data/spec/controllers/concerns_controller_spec.rb +2 -2
- data/spec/controllers/extended_controller_spec.rb +14 -0
- data/spec/controllers/memes_controller_spec.rb +10 -0
- data/spec/controllers/users_controller_spec.rb +115 -75
- data/spec/dummy/app/controllers/application_controller.rb +5 -1
- data/spec/dummy/app/controllers/concerns/extending_concern.rb +12 -0
- data/spec/dummy/app/controllers/concerns/sample_controller.rb +5 -5
- data/spec/dummy/app/controllers/extended_controller.rb +14 -0
- data/spec/dummy/app/controllers/pets_controller.rb +408 -0
- data/spec/dummy/app/controllers/pets_using_auto_views_controller.rb +73 -0
- data/spec/dummy/app/controllers/pets_using_self_describing_classes_controller.rb +95 -0
- data/spec/dummy/app/controllers/tagged_cats_controller.rb +32 -0
- data/spec/dummy/app/controllers/tagged_dogs_controller.rb +15 -0
- data/spec/dummy/app/controllers/twitter_example_controller.rb +5 -0
- data/spec/dummy/app/controllers/users_controller.rb +19 -11
- data/spec/dummy/components/test_engine/Gemfile +6 -0
- data/spec/dummy/components/test_engine/app/controllers/test_engine/application_controller.rb +4 -0
- data/spec/dummy/components/test_engine/app/controllers/test_engine/memes_controller.rb +37 -0
- data/spec/dummy/components/test_engine/config/routes.rb +3 -0
- data/spec/dummy/components/test_engine/db/.gitkeep +0 -0
- data/spec/dummy/components/test_engine/lib/test_engine.rb +7 -0
- data/spec/dummy/components/test_engine/test_engine.gemspec +11 -0
- data/spec/dummy/config/application.rb +5 -0
- data/spec/dummy/config/environments/development.rb +3 -0
- data/spec/dummy/config/environments/production.rb +3 -0
- data/spec/dummy/config/environments/test.rb +3 -0
- data/spec/dummy/config/initializers/apipie.rb +3 -1
- data/spec/dummy/config/routes.rb +24 -1
- data/spec/lib/extractor/writer_spec.rb +32 -4
- data/spec/lib/file_handler_spec.rb +18 -0
- data/spec/lib/method_description_spec.rb +34 -0
- data/spec/lib/swagger/openapi_2_0_schema.json +1607 -0
- data/spec/lib/swagger/rake_swagger_spec.rb +139 -0
- data/spec/lib/swagger/response_validation_spec.rb +104 -0
- data/spec/lib/swagger/swagger_dsl_spec.rb +658 -0
- data/spec/lib/validator_spec.rb +58 -0
- data/spec/lib/validators/array_validator_spec.rb +28 -8
- data/spec/spec_helper.rb +68 -0
- metadata +75 -23
- data/Gemfile +0 -7
- data/Gemfile.rails32 +0 -6
- data/Gemfile.rails40 +0 -5
- 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 :
|
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 :
|
200
|
+
render :plain => "Not Found", :status => 404 and return
|
201
201
|
end
|
202
202
|
|
203
|
-
render :
|
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 :
|
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 :
|
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 :
|
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 :
|
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 :
|
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 :
|
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 :
|
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,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
|
File without changes
|
@@ -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
|
@@ -1,12 +1,14 @@
|
|
1
1
|
Apipie.configure do |config|
|
2
2
|
config.app_name = "Test app"
|
3
3
|
config.copyright = "© 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
|
|
data/spec/dummy/config/routes.rb
CHANGED
@@ -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',
|
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
|
-
|
61
|
-
|
62
|
-
Apipie.configuration.doc_path
|
63
|
-
|
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
|