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
@@ -218,22 +218,22 @@ RSpec.shared_context 'representable swagger example' do
218
218
 
219
219
  let(:swagger_nested_type) do
220
220
  {
221
- 'ApiError' => { 'type' => 'object', 'properties' => { 'code' => { 'description' => 'status code', 'type' => 'integer', 'format' => 'int32' }, 'message' => { 'description' => 'error message', 'type' => 'string' } }, 'description' => 'This returns something' },
222
- 'UseItemResponseAsType' => { 'type' => 'object', 'properties' => { 'description' => { 'description' => '', 'type' => 'string' }, 'responses' => { 'description' => '', 'type' => 'ResponseItem' } }, 'description' => 'This returns something' }
221
+ 'ApiError' => { 'type' => 'object', 'properties' => { 'code' => { 'description' => 'status code', 'type' => 'integer', 'format' => 'int32' }, 'message' => { 'description' => 'error message', 'type' => 'string' } }, 'description' => 'ApiError model' },
222
+ 'UseItemResponseAsType' => { 'type' => 'object', 'properties' => { 'description' => { 'description' => '', 'type' => 'string' }, 'responses' => { 'description' => '', 'type' => 'ResponseItem' } }, 'description' => 'UseItemResponseAsType model' }
223
223
  }
224
224
  end
225
225
 
226
226
  let(:swagger_entity_as_response_object) do
227
227
  {
228
- 'ApiError' => { 'type' => 'object', 'properties' => { 'code' => { 'description' => 'status code', 'type' => 'integer', 'format' => 'int32' }, 'message' => { 'description' => 'error message', 'type' => 'string' } }, 'description' => 'This returns something' },
228
+ 'ApiError' => { 'type' => 'object', 'properties' => { 'code' => { 'description' => 'status code', 'type' => 'integer', 'format' => 'int32' }, 'message' => { 'description' => 'error message', 'type' => 'string' } }, 'description' => 'ApiError model' },
229
229
  'ResponseItem' => { 'type' => 'object', 'properties' => { 'id' => { 'description' => '', 'type' => 'integer', 'format' => 'int32' }, 'name' => { 'description' => '', 'type' => 'string' } } },
230
- 'UseResponse' => { 'type' => 'object', 'properties' => { 'description' => { 'description' => '', 'type' => 'string' }, '$responses' => { 'type' => 'array', 'items' => { '$ref' => '#/definitions/ResponseItem' }, 'description' => '' } }, 'description' => 'This returns something' }
230
+ 'UseResponse' => { 'type' => 'object', 'properties' => { 'description' => { 'description' => '', 'type' => 'string' }, '$responses' => { 'type' => 'array', 'items' => { '$ref' => '#/definitions/ResponseItem' }, 'description' => '' } }, 'description' => 'UseResponse model' }
231
231
  }
232
232
  end
233
233
 
234
234
  let(:swagger_params_as_response_object) do
235
235
  {
236
- 'ApiError' => { 'type' => 'object', 'properties' => { 'code' => { 'description' => 'status code', 'type' => 'integer', 'format' => 'int32' }, 'message' => { 'description' => 'error message', 'type' => 'string' } }, 'description' => 'This returns something' }
236
+ 'ApiError' => { 'type' => 'object', 'properties' => { 'code' => { 'description' => 'status code', 'type' => 'integer', 'format' => 'int32' }, 'message' => { 'description' => 'error message', 'type' => 'string' } }, 'description' => 'ApiError model' }
237
237
  }
238
238
  end
239
239
 
@@ -372,7 +372,7 @@ RSpec.shared_context 'representable swagger example' do
372
372
  'type' => 'object',
373
373
  'required' => ['elements'],
374
374
  'properties' => { 'elements' => { 'type' => 'array', 'items' => { '$ref' => '#/definitions/QueryInputElement' }, 'description' => 'Set of configuration' } },
375
- 'description' => 'nested route inside namespace'
375
+ 'description' => 'QueryInput model'
376
376
  },
377
377
  'QueryInputElement' => {
378
378
  'type' => 'object',
@@ -382,7 +382,7 @@ RSpec.shared_context 'representable swagger example' do
382
382
  'ApiError' => {
383
383
  'type' => 'object',
384
384
  'properties' => { 'code' => { 'type' => 'integer', 'format' => 'int32', 'description' => 'status code' }, 'message' => { 'type' => 'string', 'description' => 'error message' } },
385
- 'description' => 'This gets Things.'
385
+ 'description' => 'ApiError model'
386
386
  },
387
387
  'Something' => {
388
388
  'type' => 'object',
@@ -392,7 +392,7 @@ RSpec.shared_context 'representable swagger example' do
392
392
  'links' => { 'type' => 'array', 'items' => { 'description' => '', 'type' => 'link' } },
393
393
  'others' => { 'description' => '', 'type' => 'text' }
394
394
  },
395
- 'description' => 'This gets Things.'
395
+ 'description' => 'Something model'
396
396
  }
397
397
  }
398
398
  }
@@ -9,6 +9,7 @@ RSpec.shared_context 'namespace example' do
9
9
  namespace :hudson do
10
10
  desc 'Document root'
11
11
  get '/' do
12
+ { message: 'hi' }
12
13
  end
13
14
  end
14
15
 
@@ -19,7 +19,7 @@ describe 'hidden flag enables a single endpoint parameter to be excluded from th
19
19
  requires :name, type: String, documentation: { desc: 'name' }
20
20
  optional :favourite_color, type: String, documentation: { desc: 'I should not be anywhere', hidden: true }
21
21
  optional :proc_param, type: String, documentation: { desc: 'I should not be anywhere', hidden: proc { true } }
22
- optional :proc_with_token, type: String, documentation: { desc: 'I may be somewhere', hidden: proc { |token_owner = nil| token_owner.nil? } }
22
+ optional :proc_with_token, type: String, documentation: { desc: 'I may be somewhere', hidden: proc { false } }
23
23
  end
24
24
 
25
25
  post do
@@ -81,6 +81,7 @@ describe 'swagger spec v2.0' do
81
81
  requires :id, type: Integer
82
82
  end
83
83
  delete '/dummy/:id' do
84
+ {}
84
85
  end
85
86
 
86
87
  namespace :other_thing do
@@ -189,7 +189,7 @@ describe 'setting of param type, such as `query`, `path`, `formData`, `body`, `h
189
189
  'type' => 'object',
190
190
  'properties' => {
191
191
  'data' => {
192
- '$ref' => '#/definitions/ApiResponse',
192
+ '$ref' => '#/definitions/NestedModule_ApiResponse',
193
193
  'description' => 'request data'
194
194
  }
195
195
  },
@@ -207,7 +207,7 @@ describe 'setting of param type, such as `query`, `path`, `formData`, `body`, `h
207
207
  end
208
208
 
209
209
  specify do
210
- expect(subject['definitions']['ApiResponse']).not_to be_nil
210
+ expect(subject['definitions']['NestedModule_ApiResponse']).not_to be_nil
211
211
  end
212
212
 
213
213
  specify do
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe 'response' do
6
+ include_context "#{MODEL_PARSER} swagger example"
7
+
8
+ before :all do
9
+ module TheApi
10
+ class ResponseApiModels < Grape::API
11
+ format :json
12
+
13
+ desc 'This returns something',
14
+ success: [{ code: 200 }],
15
+ failure: [
16
+ { code: 400, message: 'NotFound', model: '' },
17
+ { code: 404, message: 'BadRequest', model: Entities::ApiError }
18
+ ]
19
+ get '/use-response' do
20
+ { 'declared_params' => declared(params) }
21
+ end
22
+
23
+ add_swagger_documentation(models: [Entities::UseResponse])
24
+ end
25
+ end
26
+ end
27
+
28
+ def app
29
+ TheApi::ResponseApiModels
30
+ end
31
+
32
+ describe 'uses entity as response object implicitly with route name' do
33
+ subject do
34
+ get '/swagger_doc/use-response'
35
+ JSON.parse(last_response.body)
36
+ end
37
+
38
+ specify do
39
+ expect(subject['paths']['/use-response']['get']).to eql(
40
+ 'description' => 'This returns something',
41
+ 'produces' => ['application/json'],
42
+ 'responses' => {
43
+ '200' => { 'description' => 'This returns something', 'schema' => { '$ref' => '#/definitions/UseResponse' } },
44
+ '400' => { 'description' => 'NotFound' },
45
+ '404' => { 'description' => 'BadRequest', 'schema' => { '$ref' => '#/definitions/ApiError' } }
46
+ },
47
+ 'tags' => ['use-response'],
48
+ 'operationId' => 'getUseResponse'
49
+ )
50
+ expect(subject['definitions']).to eql(swagger_entity_as_response_object)
51
+ end
52
+ end
53
+ end
@@ -80,6 +80,7 @@ describe 'swagger spec v2.0' do
80
80
  requires :id, type: Integer
81
81
  end
82
82
  delete '/dummy/:id' do
83
+ {}
83
84
  end
84
85
 
85
86
  namespace :other_thing do
@@ -11,6 +11,7 @@ describe 'Boolean Params' do
11
11
  requires :a_boolean, type: Grape::API::Boolean
12
12
  end
13
13
  post :splines do
14
+ { message: 'hi' }
14
15
  end
15
16
 
16
17
  add_swagger_documentation
@@ -11,6 +11,7 @@ describe 'Float Params' do
11
11
  requires :a_float, type: Float
12
12
  end
13
13
  post :splines do
14
+ { message: 'hi' }
14
15
  end
15
16
 
16
17
  add_swagger_documentation
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe 'Inheritance and Discriminator' do
6
+ before :all do
7
+ module InheritanceTest
8
+ module Entities
9
+ # example from https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#models-with-polymorphism-supports
10
+ class Pet < Grape::Entity
11
+ expose :type, documentation: {
12
+ type: 'string',
13
+ is_discriminator: true,
14
+ required: true
15
+ }
16
+ expose :name, documentation: {
17
+ type: 'string',
18
+ required: true
19
+ }
20
+ end
21
+
22
+ class Cat < Pet
23
+ expose :huntingSkill, documentation: {
24
+ type: 'string',
25
+ description: 'The measured skill for hunting',
26
+ default: 'lazy',
27
+ values: %w[
28
+ clueless
29
+ lazy
30
+ adventurous
31
+ aggressive
32
+ ]
33
+ }
34
+ end
35
+ end
36
+ class NameApi < Grape::API
37
+ add_swagger_documentation models: [Entities::Pet, Entities::Cat]
38
+ end
39
+ end
40
+ end
41
+
42
+ context 'Parent model' do
43
+ let(:app) { InheritanceTest::NameApi }
44
+
45
+ subject do
46
+ get '/swagger_doc'
47
+ JSON.parse(last_response.body)['definitions']
48
+ end
49
+
50
+ specify do
51
+ subject['InheritanceTest_Entities_Pet'].key?('discriminator')
52
+ subject['InheritanceTest_Entities_Pet']['discriminator'] = 'type'
53
+ subject['InheritanceTest_Entities_Cat'].key?('allOf')
54
+ end
55
+ end
56
+ end
@@ -17,6 +17,7 @@ describe 'namespace tags check while using prefix and version' do
17
17
  namespace :hudson do
18
18
  desc 'Document root'
19
19
  get '/' do
20
+ { message: 'hi' }
20
21
  end
21
22
  end
22
23
 
@@ -16,6 +16,7 @@ describe 'Params Multi Types' do
16
16
  requires :another_input, type: [String, Integer]
17
17
  end
18
18
  post :action do
19
+ { message: 'hi' }
19
20
  end
20
21
 
21
22
  add_swagger_documentation
@@ -61,6 +62,7 @@ describe 'Params Multi Types' do
61
62
  requires :another_input, type: [String, Integer]
62
63
  end
63
64
  post :action do
65
+ { message: 'hi' }
64
66
  end
65
67
 
66
68
  add_swagger_documentation
@@ -11,12 +11,14 @@ describe 'Params Types' do
11
11
  requires :input, type: String
12
12
  end
13
13
  post :action do
14
+ { message: 'hi' }
14
15
  end
15
16
 
16
17
  params do
17
18
  requires :input, type: String, default: '14', documentation: { type: 'email', default: '42' }
18
19
  end
19
20
  post :action_with_doc do
21
+ { message: 'hi' }
20
22
  end
21
23
 
22
24
  add_swagger_documentation
@@ -49,6 +51,7 @@ describe 'Params Types' do
49
51
  requires :input, type: String
50
52
  end
51
53
  post :action do
54
+ { message: 'hi' }
52
55
  end
53
56
 
54
57
  add_swagger_documentation
@@ -12,24 +12,28 @@ describe 'Convert values to enum or Range' do
12
12
  requires :letter, type: String, values: %w[a b c]
13
13
  end
14
14
  post :plain_array do
15
+ { message: 'hi' }
15
16
  end
16
17
 
17
18
  params do
18
19
  requires :letter, type: String, values: proc { %w[d e f] }
19
20
  end
20
21
  post :array_in_proc do
22
+ { message: 'hi' }
21
23
  end
22
24
 
23
25
  params do
24
26
  requires :letter, type: String, values: 'a'..'z'
25
27
  end
26
28
  post :range_letter do
29
+ { message: 'hi' }
27
30
  end
28
31
 
29
32
  params do
30
33
  requires :integer, type: Integer, values: -5..5
31
34
  end
32
35
  post :range_integer do
36
+ { message: 'hi' }
33
37
  end
34
38
 
35
39
  add_swagger_documentation
@@ -107,12 +111,14 @@ describe 'Convert values to enum for float range and not arrays inside a proc',
107
111
  requires :letter, type: String, values: proc { 'string' }
108
112
  end
109
113
  post :non_array_in_proc do
114
+ { message: 'hi' }
110
115
  end
111
116
 
112
117
  params do
113
118
  requires :float, type: Float, values: -5.0..5.0
114
119
  end
115
120
  post :range_float do
121
+ { message: 'hi' }
116
122
  end
117
123
 
118
124
  add_swagger_documentation
@@ -22,6 +22,20 @@ describe 'referenceEntity' do
22
22
  expose :title, documentation: { type: 'string', desc: 'Title of the kind.' }
23
23
  expose :something, documentation: { type: Something, desc: 'Something interesting.' }
24
24
  end
25
+
26
+ class Base < Grape::Entity
27
+ def self.entity_name
28
+ parts = to_s.split('::')
29
+
30
+ "MyAPI::#{parts.last}"
31
+ end
32
+
33
+ expose :title, documentation: { type: 'string', desc: 'Title of the parent.' }
34
+ end
35
+
36
+ class Child < Base
37
+ expose :child, documentation: { type: 'string', desc: 'Child property.' }
38
+ end
25
39
  end
26
40
 
27
41
  class ResponseModelApi < Grape::API
@@ -40,6 +54,16 @@ describe 'referenceEntity' do
40
54
  present kind, with: Entities::Kind
41
55
  end
42
56
 
57
+ desc 'This returns a child entity',
58
+ entity: Entities::Child,
59
+ http_codes: [
60
+ { code: 200, message: 'OK', model: Entities::Child }
61
+ ]
62
+ get '/child' do
63
+ child = OpenStruct.new text: 'child'
64
+ present child, with: Entities::Child
65
+ end
66
+
43
67
  add_swagger_documentation # models: [MyAPI::Entities::Something, MyAPI::Entities::Kind]
44
68
  end
45
69
  end
@@ -49,36 +73,57 @@ describe 'referenceEntity' do
49
73
  MyAPI::ResponseModelApi
50
74
  end
51
75
 
52
- subject do
53
- get '/swagger_doc/kind'
54
- JSON.parse(last_response.body)
76
+ describe 'kind' do
77
+ subject do
78
+ get '/swagger_doc/kind'
79
+ JSON.parse(last_response.body)
80
+ end
81
+
82
+ it 'should document specified models' do
83
+ expect(subject['paths']['/kind']['get']['parameters']).to eq [{
84
+ 'in' => 'query',
85
+ 'name' => 'something',
86
+ 'description' => 'Something interesting.',
87
+ 'type' => 'SomethingCustom',
88
+ 'required' => false
89
+ }]
90
+
91
+ expect(subject['definitions'].keys).to include 'SomethingCustom'
92
+ expect(subject['definitions']['SomethingCustom']).to eq(
93
+ 'type' => 'object', 'properties' => { 'text' => { 'type' => 'string', 'description' => 'Content of something.' } }
94
+ )
95
+
96
+ expect(subject['definitions'].keys).to include 'KindCustom'
97
+ expect(subject['definitions']['KindCustom']).to eq(
98
+ 'type' => 'object',
99
+ 'properties' => {
100
+ 'title' => { 'type' => 'string', 'description' => 'Title of the kind.' },
101
+ 'something' => {
102
+ '$ref' => '#/definitions/SomethingCustom',
103
+ 'description' => 'Something interesting.'
104
+ }
105
+ },
106
+ 'description' => 'KindCustom model'
107
+ )
108
+ end
55
109
  end
56
110
 
57
- it 'should document specified models' do
58
- expect(subject['paths']['/kind']['get']['parameters']).to eq [{
59
- 'in' => 'query',
60
- 'name' => 'something',
61
- 'description' => 'Something interesting.',
62
- 'type' => 'SomethingCustom',
63
- 'required' => false
64
- }]
65
-
66
- expect(subject['definitions'].keys).to include 'SomethingCustom'
67
- expect(subject['definitions']['SomethingCustom']).to eq(
68
- 'type' => 'object', 'properties' => { 'text' => { 'type' => 'string', 'description' => 'Content of something.' } }
69
- )
70
-
71
- expect(subject['definitions'].keys).to include 'KindCustom'
72
- expect(subject['definitions']['KindCustom']).to eq(
73
- 'type' => 'object',
74
- 'properties' => {
75
- 'title' => { 'type' => 'string', 'description' => 'Title of the kind.' },
76
- 'something' => {
77
- '$ref' => '#/definitions/SomethingCustom',
78
- 'description' => 'Something interesting.'
79
- }
80
- },
81
- 'description' => 'This returns kind and something or an error'
82
- )
111
+ describe 'child' do
112
+ subject do
113
+ get '/swagger_doc/child'
114
+ JSON.parse(last_response.body)
115
+ end
116
+
117
+ it 'should document specified models' do
118
+ expect(subject['definitions'].keys).to include 'MyAPI::Child'
119
+ expect(subject['definitions']['MyAPI::Child']).to eq(
120
+ 'type' => 'object',
121
+ 'properties' => {
122
+ 'title' => { 'type' => 'string', 'description' => 'Title of the parent.' },
123
+ 'child' => { 'type' => 'string', 'description' => 'Child property.' }
124
+ },
125
+ 'description' => 'MyAPI::Child model'
126
+ )
127
+ end
83
128
  end
84
129
  end