grape-swagger 1.0.0 → 1.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +94 -1
  3. data/.rubocop_todo.yml +1 -1
  4. data/.travis.yml +14 -8
  5. data/CHANGELOG.md +56 -6
  6. data/Gemfile +9 -4
  7. data/README.md +191 -12
  8. data/UPGRADING.md +34 -0
  9. data/grape-swagger.gemspec +1 -1
  10. data/lib/grape-swagger.rb +7 -4
  11. data/lib/grape-swagger/doc_methods.rb +65 -62
  12. data/lib/grape-swagger/doc_methods/build_model_definition.rb +53 -2
  13. data/lib/grape-swagger/doc_methods/data_type.rb +5 -5
  14. data/lib/grape-swagger/doc_methods/format_data.rb +2 -2
  15. data/lib/grape-swagger/doc_methods/operation_id.rb +2 -2
  16. data/lib/grape-swagger/doc_methods/parse_params.rb +19 -4
  17. data/lib/grape-swagger/endpoint.rb +73 -31
  18. data/lib/grape-swagger/rake/oapi_tasks.rb +12 -2
  19. data/lib/grape-swagger/version.rb +1 -1
  20. data/spec/issues/427_entity_as_string_spec.rb +1 -1
  21. data/spec/issues/430_entity_definitions_spec.rb +7 -5
  22. data/spec/issues/537_enum_values_spec.rb +1 -0
  23. data/spec/issues/776_multiple_presents_spec.rb +56 -0
  24. data/spec/issues/784_extensions_on_params_spec.rb +38 -0
  25. data/spec/issues/809_utf8_routes_spec.rb +55 -0
  26. data/spec/lib/data_type_spec.rb +12 -0
  27. data/spec/lib/move_params_spec.rb +2 -2
  28. data/spec/lib/oapi_tasks_spec.rb +15 -5
  29. data/spec/support/empty_model_parser.rb +1 -2
  30. data/spec/support/mock_parser.rb +1 -2
  31. data/spec/support/model_parsers/entity_parser.rb +8 -8
  32. data/spec/support/model_parsers/mock_parser.rb +8 -8
  33. data/spec/support/model_parsers/representable_parser.rb +8 -8
  34. data/spec/support/namespace_tags.rb +1 -0
  35. data/spec/swagger_v2/api_swagger_v2_hide_param_spec.rb +1 -1
  36. data/spec/swagger_v2/api_swagger_v2_mounted_spec.rb +1 -0
  37. data/spec/swagger_v2/api_swagger_v2_param_type_body_spec.rb +2 -2
  38. data/spec/swagger_v2/api_swagger_v2_response_with_models_spec.rb +53 -0
  39. data/spec/swagger_v2/api_swagger_v2_spec.rb +1 -0
  40. data/spec/swagger_v2/boolean_params_spec.rb +1 -0
  41. data/spec/swagger_v2/float_api_spec.rb +1 -0
  42. data/spec/swagger_v2/inheritance_and_discriminator_spec.rb +56 -0
  43. data/spec/swagger_v2/namespace_tags_prefix_spec.rb +1 -0
  44. data/spec/swagger_v2/param_multi_type_spec.rb +2 -0
  45. data/spec/swagger_v2/param_type_spec.rb +3 -0
  46. data/spec/swagger_v2/param_values_spec.rb +6 -0
  47. data/spec/swagger_v2/reference_entity_spec.rb +74 -29
  48. data/spec/swagger_v2/security_requirement_spec.rb +2 -2
  49. data/spec/swagger_v2/simple_mounted_api_spec.rb +1 -0
  50. metadata +19 -9
@@ -10,17 +10,25 @@ module GrapeSwagger
10
10
  include Rack::Test::Methods
11
11
 
12
12
  attr_reader :oapi
13
- attr_reader :api_class
14
13
 
15
14
  def initialize(api_class)
16
15
  super()
17
16
 
18
- @api_class = api_class
17
+ if api_class.is_a? String
18
+ @api_class_name = api_class
19
+ else
20
+ @api_class = api_class
21
+ end
22
+
19
23
  define_tasks
20
24
  end
21
25
 
22
26
  private
23
27
 
28
+ def api_class
29
+ @api_class ||= @api_class_name.constantize
30
+ end
31
+
24
32
  def define_tasks
25
33
  namespace :oapi do
26
34
  fetch
@@ -66,6 +74,7 @@ module GrapeSwagger
66
74
 
67
75
  # helper methods
68
76
  #
77
+ # rubocop:disable Style/StringConcatenation
69
78
  def make_request
70
79
  get url_for
71
80
 
@@ -75,6 +84,7 @@ module GrapeSwagger
75
84
  )
76
85
  ) + "\n"
77
86
  end
87
+ # rubocop:enable Style/StringConcatenation
78
88
 
79
89
  def url_for
80
90
  oapi_route = api_class.routes[-2]
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module GrapeSwagger
4
- VERSION = '1.0.0'
4
+ VERSION = '1.3.1'
5
5
  end
@@ -35,5 +35,5 @@ describe '#427 nested entity given as string' do
35
35
  JSON.parse(last_response.body)['definitions']
36
36
  end
37
37
 
38
- specify { expect(subject.keys).to include 'RoleEntity', 'WithoutRole' }
38
+ specify { expect(subject.keys).to include 'RoleEntity', 'Permission_WithoutRole' }
39
39
  end
@@ -55,6 +55,8 @@ describe 'definition names' do
55
55
  class Class7
56
56
  class SeventhEntity < Class6::SixthEntity
57
57
  expose :seventh_thing
58
+
59
+ private_class_method :entity_name
58
60
  end
59
61
  end
60
62
  end
@@ -82,11 +84,11 @@ describe 'definition names' do
82
84
  JSON.parse(last_response.body)['definitions']
83
85
  end
84
86
 
85
- specify { expect(subject).to include 'Class1' }
86
- specify { expect(subject).to include 'Class2' }
87
+ specify { expect(subject).to include 'TestDefinition_DummyEntities_WithVeryLongName_AnotherGroupingModule_Class1' }
88
+ specify { expect(subject).to include 'TestDefinition_DummyEntities_WithVeryLongName_AnotherGroupingModule_Class2' }
87
89
  specify { expect(subject).to include 'FooKlass' }
88
- specify { expect(subject).to include 'FourthEntity' }
89
- specify { expect(subject).to include 'FithEntity' }
90
+ specify { expect(subject).to include 'TestDefinition_DummyEntities_WithVeryLongName_AnotherGroupingModule_Class4_FourthEntity' }
91
+ specify { expect(subject).to include 'TestDefinition_DummyEntities_WithVeryLongName_AnotherGroupingModule_Class5_FithEntity' }
90
92
  specify { expect(subject).to include 'BarKlass' }
91
- specify { expect(subject).to include 'SeventhEntity' }
93
+ specify { expect(subject).to include 'TestDefinition_DummyEntities_WithVeryLongName_AnotherGroupingModule_Class7_SeventhEntity' }
92
94
  end
@@ -15,6 +15,7 @@ describe '#537 enum values spec' do
15
15
  desc 'create account',
16
16
  success: Spec
17
17
  get do
18
+ { message: 'hi' }
18
19
  end
19
20
  end
20
21
 
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe '#776 multiple presents spec' do
6
+ include_context "#{MODEL_PARSER} swagger example"
7
+
8
+ let(:app) do
9
+ Class.new(Grape::API) do
10
+ namespace :issue_776 do
11
+ desc 'Get multiple presents',
12
+ success: [
13
+ { model: Entities::EnumValues, as: :gender },
14
+ { model: Entities::Something, as: :somethings, is_array: true }
15
+ ]
16
+
17
+ get do
18
+ present :gender, { number: 1, gender: 'Male' }, with: Entities::EnumValues
19
+ present :somethings, [
20
+ { id: 1, text: 'element_1', links: %w[link1 link2] },
21
+ { id: 2, text: 'element_2', links: %w[link1 link2] }
22
+ ], with: Entities::Something, is_array: true
23
+ end
24
+ end
25
+
26
+ add_swagger_documentation format: :json
27
+ end
28
+ end
29
+
30
+ subject do
31
+ get '/swagger_doc'
32
+ JSON.parse(last_response.body)
33
+ end
34
+
35
+ let(:definitions) { subject['definitions'] }
36
+ let(:schema) { subject['paths']['/issue_776']['get']['responses']['200']['schema'] }
37
+
38
+ specify { expect(definitions.keys).to include 'EnumValues', 'Something' }
39
+
40
+ specify do
41
+ expect(schema).to eql({
42
+ 'properties' => {
43
+ 'somethings' => {
44
+ 'items' => {
45
+ '$ref' => '#/definitions/Something'
46
+ },
47
+ 'type' => 'array'
48
+ },
49
+ 'gender' => {
50
+ '$ref' => '#/definitions/EnumValues'
51
+ }
52
+ },
53
+ 'type' => 'object'
54
+ })
55
+ end
56
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe '#532 allow custom format' do
6
+ let(:app) do
7
+ Class.new(Grape::API) do
8
+ namespace :issue_784 do
9
+ params do
10
+ requires :logs, type: String, documentation: { format: 'log', x: { name: 'Log' } }
11
+ optional :phone_number, type: Integer, documentation: { format: 'phone_number', x: { name: 'PhoneNumber' } }
12
+ end
13
+
14
+ post do
15
+ present params
16
+ end
17
+ end
18
+
19
+ add_swagger_documentation format: :json
20
+ end
21
+ end
22
+
23
+ subject do
24
+ get '/swagger_doc'
25
+ JSON.parse(last_response.body)
26
+ end
27
+
28
+ let(:parameters) { subject['paths']['/issue_784']['post']['parameters'] }
29
+
30
+ specify do
31
+ expect(parameters).to eql(
32
+ [
33
+ { 'in' => 'formData', 'name' => 'logs', 'type' => 'string', 'format' => 'log', 'required' => true, 'x-name' => 'Log' },
34
+ { 'in' => 'formData', 'name' => 'phone_number', 'type' => 'integer', 'format' => 'phone_number', 'required' => false, 'x-name' => 'PhoneNumber' }
35
+ ]
36
+ )
37
+ end
38
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe '#605 root route documentation' do
6
+ let(:app) do
7
+ Class.new(Grape::API) do
8
+ resource :grunnbeløp do
9
+ desc 'returnerer grunnbeløp'
10
+ get do
11
+ { message: 'hello world' }
12
+ end
13
+ end
14
+
15
+ resource :εσόδων do
16
+ desc 'εσόδων'
17
+ get do
18
+ { message: 'hello world' }
19
+ end
20
+ end
21
+
22
+ resource :数 do
23
+ desc '数'
24
+ get do
25
+ { message: 'hello world' }
26
+ end
27
+ end
28
+
29
+ resource :amount do
30
+ desc 'returns amount'
31
+ get do
32
+ { message: 'hello world' }
33
+ end
34
+ end
35
+
36
+ resource :👍 do
37
+ desc 'returns 👍'
38
+ get do
39
+ { message: 'hello world' }
40
+ end
41
+ end
42
+
43
+ add_swagger_documentation
44
+ end
45
+ end
46
+
47
+ subject do
48
+ get '/swagger_doc'
49
+ JSON.parse(last_response.body)['paths']
50
+ end
51
+
52
+ specify do
53
+ expect(subject.keys).to match_array ['/grunnbeløp', '/amount', '/εσόδων', '/数']
54
+ end
55
+ end
@@ -49,6 +49,18 @@ describe GrapeSwagger::DocMethods::DataType do
49
49
  it { is_expected.to eq 'MyInteger' }
50
50
  end
51
51
 
52
+ describe 'Types in array with inherited entity_name' do
53
+ before do
54
+ stub_const 'EntityBase', Class.new
55
+ allow(EntityBase).to receive(:entity_name).and_return 'MyInteger'
56
+ stub_const 'MyEntity', Class.new(EntityBase)
57
+ end
58
+
59
+ let(:value) { { type: '[MyEntity]' } }
60
+
61
+ it { is_expected.to eq 'MyInteger' }
62
+ end
63
+
52
64
  describe 'Rack::Multipart::UploadedFile' do
53
65
  let(:value) { { type: Rack::Multipart::UploadedFile } }
54
66
 
@@ -97,7 +97,7 @@ describe GrapeSwagger::DocMethods::MoveParams do
97
97
  let(:route_options) { { requirements: {} } }
98
98
  describe 'POST' do
99
99
  let(:params) { paths[path][:post][:parameters] }
100
- let(:route) { Grape::Router::Route.new('POST', path.dup, route_options) }
100
+ let(:route) { Grape::Router::Route.new('POST', path.dup, **route_options) }
101
101
 
102
102
  specify do
103
103
  subject.to_definition(path, params, route, definitions)
@@ -113,7 +113,7 @@ describe GrapeSwagger::DocMethods::MoveParams do
113
113
 
114
114
  describe 'POST' do
115
115
  let(:params) { paths['/in_body/{key}'][:put][:parameters] }
116
- let(:route) { Grape::Router::Route.new('PUT', path.dup, route_options) }
116
+ let(:route) { Grape::Router::Route.new('PUT', path.dup, **route_options) }
117
117
 
118
118
  specify do
119
119
  subject.to_definition(path, params, route, definitions)
@@ -3,8 +3,8 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  RSpec.describe GrapeSwagger::Rake::OapiTasks do
6
- let(:api) do
7
- item = Class.new(Grape::API) do
6
+ module Api
7
+ class Item < Grape::API
8
8
  version 'v1', using: :path
9
9
 
10
10
  namespace :item do
@@ -16,14 +16,24 @@ RSpec.describe GrapeSwagger::Rake::OapiTasks do
16
16
  end
17
17
  end
18
18
 
19
- Class.new(Grape::API) do
19
+ class Base < Grape::API
20
20
  prefix :api
21
- mount item
21
+ mount Api::Item
22
22
  add_swagger_documentation add_version: true
23
23
  end
24
24
  end
25
25
 
26
- subject { described_class.new(api) }
26
+ subject { described_class.new(Api::Base) }
27
+
28
+ describe '.new' do
29
+ it 'accepts class name as a constant' do
30
+ expect(described_class.new(::Api::Base).send(:api_class)).to eq(Api::Base)
31
+ end
32
+
33
+ it 'accepts class name as a string' do
34
+ expect(described_class.new('::Api::Base').send(:api_class)).to eq(Api::Base)
35
+ end
36
+ end
27
37
 
28
38
  describe '#make_request' do
29
39
  describe 'complete documentation' do
@@ -5,8 +5,7 @@ end
5
5
 
6
6
  module GrapeSwagger
7
7
  class EmptyModelParser
8
- attr_reader :model
9
- attr_reader :endpoint
8
+ attr_reader :model, :endpoint
10
9
 
11
10
  def initialize(model, endpoint)
12
11
  @model = model
@@ -2,8 +2,7 @@
2
2
 
3
3
  module GrapeSwagger
4
4
  class MockParser
5
- attr_reader :model
6
- attr_reader :endpoint
5
+ attr_reader :model, :endpoint
7
6
 
8
7
  def initialize(model, endpoint)
9
8
  @model = model
@@ -145,23 +145,23 @@ RSpec.shared_context 'entity swagger example' do
145
145
 
146
146
  let(:swagger_nested_type) do
147
147
  {
148
- 'ApiError' => { 'type' => 'object', 'properties' => { 'code' => { 'type' => 'integer', 'format' => 'int32', 'description' => 'status code' }, 'message' => { 'type' => 'string', 'description' => 'error message' } }, 'description' => 'This returns something' },
148
+ 'ApiError' => { 'type' => 'object', 'properties' => { 'code' => { 'type' => 'integer', 'format' => 'int32', 'description' => 'status code' }, 'message' => { 'type' => 'string', 'description' => 'error message' } }, 'description' => 'ApiError model' },
149
149
  'ResponseItem' => { 'type' => 'object', 'properties' => { 'id' => { 'type' => 'integer', 'format' => 'int32' }, 'name' => { 'type' => 'string' } } },
150
- 'UseItemResponseAsType' => { 'type' => 'object', 'properties' => { 'description' => { 'type' => 'string' }, 'responses' => { '$ref' => '#/definitions/ResponseItem' } }, 'description' => 'This returns something' }
150
+ 'UseItemResponseAsType' => { 'type' => 'object', 'properties' => { 'description' => { 'type' => 'string' }, 'responses' => { '$ref' => '#/definitions/ResponseItem' } }, 'description' => 'UseItemResponseAsType model' }
151
151
  }
152
152
  end
153
153
 
154
154
  let(:swagger_entity_as_response_object) do
155
155
  {
156
- 'ApiError' => { 'type' => 'object', 'properties' => { 'code' => { 'type' => 'integer', 'format' => 'int32', 'description' => 'status code' }, 'message' => { 'type' => 'string', 'description' => 'error message' } }, 'description' => 'This returns something' },
156
+ 'ApiError' => { 'type' => 'object', 'properties' => { 'code' => { 'type' => 'integer', 'format' => 'int32', 'description' => 'status code' }, 'message' => { 'type' => 'string', 'description' => 'error message' } }, 'description' => 'ApiError model' },
157
157
  'ResponseItem' => { 'type' => 'object', 'properties' => { 'id' => { 'type' => 'integer', 'format' => 'int32' }, 'name' => { 'type' => 'string' } } },
158
- 'UseResponse' => { 'type' => 'object', 'properties' => { 'description' => { 'type' => 'string' }, '$responses' => { 'type' => 'array', 'items' => { '$ref' => '#/definitions/ResponseItem' } } }, 'description' => 'This returns something' }
158
+ 'UseResponse' => { 'type' => 'object', 'properties' => { 'description' => { 'type' => 'string' }, '$responses' => { 'type' => 'array', 'items' => { '$ref' => '#/definitions/ResponseItem' } } }, 'description' => 'UseResponse model' }
159
159
  }
160
160
  end
161
161
 
162
162
  let(:swagger_params_as_response_object) do
163
163
  {
164
- 'ApiError' => { 'type' => 'object', 'properties' => { 'code' => { 'description' => 'status code', 'type' => 'integer', 'format' => 'int32' }, 'message' => { 'description' => 'error message', 'type' => 'string' } }, 'description' => 'This returns something' }
164
+ 'ApiError' => { 'type' => 'object', 'properties' => { 'code' => { 'description' => 'status code', 'type' => 'integer', 'format' => 'int32' }, 'message' => { 'description' => 'error message', 'type' => 'string' } }, 'description' => 'ApiError model' }
165
165
  }
166
166
  end
167
167
 
@@ -300,7 +300,7 @@ RSpec.shared_context 'entity swagger example' do
300
300
  'type' => 'object',
301
301
  'required' => ['elements'],
302
302
  'properties' => { 'elements' => { 'type' => 'array', 'items' => { '$ref' => '#/definitions/QueryInputElement' }, 'description' => 'Set of configuration' } },
303
- 'description' => 'nested route inside namespace'
303
+ 'description' => 'QueryInput model'
304
304
  },
305
305
  'QueryInputElement' => {
306
306
  'type' => 'object',
@@ -310,7 +310,7 @@ RSpec.shared_context 'entity swagger example' do
310
310
  'ApiError' => {
311
311
  'type' => 'object',
312
312
  'properties' => { 'code' => { 'type' => 'integer', 'format' => 'int32', 'description' => 'status code' }, 'message' => { 'type' => 'string', 'description' => 'error message' } },
313
- 'description' => 'This gets Things.'
313
+ 'description' => 'ApiError model'
314
314
  },
315
315
  'Something' => {
316
316
  'type' => 'object',
@@ -320,7 +320,7 @@ RSpec.shared_context 'entity swagger example' do
320
320
  'links' => { 'type' => 'array', 'items' => { 'type' => 'link' } },
321
321
  'others' => { 'type' => 'text' }
322
322
  },
323
- 'description' => 'This gets Things.'
323
+ 'description' => 'Something model'
324
324
  }
325
325
  }
326
326
  }
@@ -112,7 +112,7 @@ RSpec.shared_context 'mock swagger example' do
112
112
  'description' => "it's a mock"
113
113
  }
114
114
  },
115
- 'description' => 'This returns something'
115
+ 'description' => 'ApiError model'
116
116
  },
117
117
  'UseItemResponseAsType' => {
118
118
  'type' => 'object',
@@ -122,7 +122,7 @@ RSpec.shared_context 'mock swagger example' do
122
122
  'description' => "it's a mock"
123
123
  }
124
124
  },
125
- 'description' => 'This returns something'
125
+ 'description' => 'UseItemResponseAsType model'
126
126
  }
127
127
  }
128
128
  end
@@ -137,7 +137,7 @@ RSpec.shared_context 'mock swagger example' do
137
137
  'description' => "it's a mock"
138
138
  }
139
139
  },
140
- 'description' => 'This returns something'
140
+ 'description' => 'UseResponse model'
141
141
  },
142
142
  'ApiError' => {
143
143
  'type' => 'object',
@@ -147,7 +147,7 @@ RSpec.shared_context 'mock swagger example' do
147
147
  'description' => "it's a mock"
148
148
  }
149
149
  },
150
- 'description' => 'This returns something'
150
+ 'description' => 'ApiError model'
151
151
  }
152
152
  }
153
153
  end
@@ -162,7 +162,7 @@ RSpec.shared_context 'mock swagger example' do
162
162
  'description' => "it's a mock"
163
163
  }
164
164
  },
165
- 'description' => 'This returns something'
165
+ 'description' => 'ApiError model'
166
166
  }
167
167
  }
168
168
  end
@@ -296,7 +296,7 @@ RSpec.shared_context 'mock swagger example' do
296
296
  'description' => "it's a mock"
297
297
  }
298
298
  },
299
- 'description' => 'nested route inside namespace'
299
+ 'description' => 'QueryInput model'
300
300
  },
301
301
  'ApiError' => {
302
302
  'type' => 'object',
@@ -306,7 +306,7 @@ RSpec.shared_context 'mock swagger example' do
306
306
  'description' => "it's a mock"
307
307
  }
308
308
  },
309
- 'description' => 'This gets Things.'
309
+ 'description' => 'ApiError model'
310
310
  },
311
311
  'Something' => {
312
312
  'type' => 'object',
@@ -316,7 +316,7 @@ RSpec.shared_context 'mock swagger example' do
316
316
  'description' => "it's a mock"
317
317
  }
318
318
  },
319
- 'description' => 'This gets Things.'
319
+ 'description' => 'Something model'
320
320
  }
321
321
  }
322
322
  }