grape-swagger 0.21.0 → 0.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -0
  3. data/.rubocop_todo.yml +1 -1
  4. data/CHANGELOG.md +24 -2
  5. data/Gemfile +5 -0
  6. data/README.md +105 -3
  7. data/example/api/endpoints.rb +16 -16
  8. data/lib/grape-swagger.rb +0 -1
  9. data/lib/grape-swagger/doc_methods.rb +1 -0
  10. data/lib/grape-swagger/doc_methods/data_type.rb +15 -3
  11. data/lib/grape-swagger/doc_methods/extensions.rb +16 -12
  12. data/lib/grape-swagger/doc_methods/move_params.rb +139 -94
  13. data/lib/grape-swagger/doc_methods/parse_params.rb +9 -7
  14. data/lib/grape-swagger/endpoint.rb +36 -17
  15. data/lib/grape-swagger/version.rb +1 -1
  16. data/spec/lib/data_type_spec.rb +24 -0
  17. data/spec/lib/endpoint_spec.rb +13 -0
  18. data/spec/lib/move_params_spec.rb +124 -116
  19. data/spec/support/model_parsers/entity_parser.rb +8 -2
  20. data/spec/support/model_parsers/mock_parser.rb +10 -0
  21. data/spec/support/model_parsers/representable_parser.rb +7 -0
  22. data/spec/support/the_paths_definitions.rb +1 -2
  23. data/spec/swagger_v2/api_swagger_v2_definitions-models_spec.rb +2 -1
  24. data/spec/swagger_v2/api_swagger_v2_detail_spec.rb +1 -1
  25. data/spec/swagger_v2/api_swagger_v2_extensions_spec.rb +22 -1
  26. data/spec/swagger_v2/api_swagger_v2_global_configuration_spec.rb +4 -1
  27. data/spec/swagger_v2/api_swagger_v2_hash_and_array_spec.rb +60 -0
  28. data/spec/swagger_v2/api_swagger_v2_headers_spec.rb +14 -9
  29. data/spec/swagger_v2/api_swagger_v2_hide_param_spec.rb +90 -0
  30. data/spec/swagger_v2/api_swagger_v2_param_type_body_nested_spec.rb +185 -110
  31. data/spec/swagger_v2/api_swagger_v2_param_type_body_spec.rb +11 -13
  32. data/spec/swagger_v2/api_swagger_v2_response_spec.rb +5 -5
  33. data/spec/swagger_v2/endpoint_versioned_path_spec.rb +19 -18
  34. data/spec/swagger_v2/namespaced_api_spec.rb +20 -0
  35. data/spec/swagger_v2/param_multi_type_spec.rb +73 -0
  36. data/spec/swagger_v2/param_type_spec.rb +54 -27
  37. data/spec/swagger_v2/params_array_spec.rb +96 -6
  38. data/spec/swagger_v2/params_nested_spec.rb +2 -2
  39. metadata +9 -3
@@ -72,7 +72,7 @@ describe 'setting of param type, such as `query`, `path`, `formData`, `body`, `h
72
72
  specify do
73
73
  expect(subject['paths']['/wo_entities/in_body']['post']['parameters']).to eql(
74
74
  [
75
- { 'name' => 'postWoEntitiesInBody', 'in' => 'body', 'required' => true, 'schema' => { '$ref' => '#/definitions/postWoEntitiesInBody' } }
75
+ { 'name' => 'WoEntitiesInBody', 'in' => 'body', 'required' => true, 'schema' => { '$ref' => '#/definitions/postWoEntitiesInBody' } }
76
76
  ]
77
77
  )
78
78
  end
@@ -94,17 +94,16 @@ describe 'setting of param type, such as `query`, `path`, `formData`, `body`, `h
94
94
  expect(subject['paths']['/wo_entities/in_body/{key}']['put']['parameters']).to eql(
95
95
  [
96
96
  { 'in' => 'path', 'name' => 'key', 'type' => 'integer', 'format' => 'int32', 'required' => true },
97
- { 'name' => 'putWoEntitiesInBodyKey', 'in' => 'body', 'required' => true, 'schema' => { '$ref' => '#/definitions/putWoEntitiesInBodyKey' } }
97
+ { 'name' => 'WoEntitiesInBody', 'in' => 'body', 'required' => true, 'schema' => { '$ref' => '#/definitions/putWoEntitiesInBody' } }
98
98
  ]
99
99
  )
100
100
  end
101
101
 
102
102
  specify do
103
- expect(subject['definitions']['putWoEntitiesInBodyKey']).to eql(
103
+ expect(subject['definitions']['putWoEntitiesInBody']).to eql(
104
104
  'description' => 'put in body /wo entity',
105
105
  'type' => 'object',
106
106
  'properties' => {
107
- 'key' => { 'type' => 'integer', 'format' => 'int32', 'readOnly' => true },
108
107
  'in_body_1' => { 'type' => 'integer', 'format' => 'int32', 'description' => 'in_body_1' },
109
108
  'in_body_2' => { 'type' => 'string', 'description' => 'in_body_2' },
110
109
  'in_body_3' => { 'type' => 'string', 'description' => 'in_body_3' }
@@ -122,19 +121,19 @@ describe 'setting of param type, such as `query`, `path`, `formData`, `body`, `h
122
121
  specify do
123
122
  expect(subject['paths']['/with_entities/in_body']['post']['parameters']).to eql(
124
123
  [
125
- { 'name' => 'ResponseItem', 'in' => 'body', 'required' => true, 'schema' => { '$ref' => '#/definitions/postRequestResponseItem' } }
124
+ { 'name' => 'WithEntitiesInBody', 'in' => 'body', 'required' => true, 'schema' => { '$ref' => '#/definitions/postWithEntitiesInBody' } }
126
125
  ]
127
126
  )
128
127
  end
129
128
 
130
129
  specify do
131
- expect(subject['definitions']['postRequestResponseItem']).to eql(
132
- 'description' => 'post in body with entity',
130
+ expect(subject['definitions']['postWithEntitiesInBody']).to eql(
133
131
  'type' => 'object',
134
132
  'properties' => {
135
133
  'name' => { 'type' => 'string', 'description' => 'name' }
136
134
  },
137
- 'required' => ['name']
135
+ 'required' => ['name'],
136
+ 'description' => 'post in body with entity'
138
137
  )
139
138
  end
140
139
 
@@ -142,19 +141,18 @@ describe 'setting of param type, such as `query`, `path`, `formData`, `body`, `h
142
141
  expect(subject['paths']['/with_entities/in_body/{id}']['put']['parameters']).to eql(
143
142
  [
144
143
  { 'in' => 'path', 'name' => 'id', 'type' => 'integer', 'format' => 'int32', 'required' => true },
145
- { 'name' => 'ResponseItem', 'in' => 'body', 'required' => true, 'schema' => { '$ref' => '#/definitions/putRequestResponseItem' } }
144
+ { 'name' => 'WithEntitiesInBody', 'in' => 'body', 'required' => true, 'schema' => { '$ref' => '#/definitions/putWithEntitiesInBody' } }
146
145
  ]
147
146
  )
148
147
  end
149
148
 
150
149
  specify do
151
- expect(subject['definitions']['putRequestResponseItem']).to eql(
152
- 'description' => 'put in body with entity',
150
+ expect(subject['definitions']['putWithEntitiesInBody']).to eql(
153
151
  'type' => 'object',
154
152
  'properties' => {
155
- 'id' => { 'type' => 'integer', 'format' => 'int32', 'readOnly' => true },
156
153
  'name' => { 'type' => 'string', 'description' => 'name' }
157
- }
154
+ },
155
+ 'description' => 'put in body with entity'
158
156
  )
159
157
  end
160
158
  end
@@ -11,7 +11,7 @@ describe 'response' do
11
11
  desc 'This returns something',
12
12
  params: Entities::UseResponse.documentation,
13
13
  failure: [{ code: 400, message: 'NotFound', model: Entities::ApiError }]
14
- post '/params_response' do
14
+ post '/params_given' do
15
15
  { 'declared_params' => declared(params) }
16
16
  end
17
17
 
@@ -83,12 +83,12 @@ describe 'response' do
83
83
 
84
84
  describe 'uses params as response object' do
85
85
  subject do
86
- get '/swagger_doc/params_response'
86
+ get '/swagger_doc/params_given'
87
87
  JSON.parse(last_response.body)
88
88
  end
89
89
 
90
90
  specify do
91
- expect(subject['paths']['/params_response']['post']).to eql(
91
+ expect(subject['paths']['/params_given']['post']).to eql(
92
92
  'summary' => 'This returns something',
93
93
  'description' => 'This returns something',
94
94
  'produces' => ['application/json'],
@@ -101,8 +101,8 @@ describe 'response' do
101
101
  '201' => { 'description' => 'This returns something' },
102
102
  '400' => { 'description' => 'NotFound', 'schema' => { '$ref' => '#/definitions/ApiError' } }
103
103
  },
104
- 'tags' => ['params_response'],
105
- 'operationId' => 'postParamsResponse'
104
+ 'tags' => ['params_given'],
105
+ 'operationId' => 'postParamsGiven'
106
106
  )
107
107
  expect(subject['definitions']).to eql(swagger_params_as_response_object)
108
108
  end
@@ -1,30 +1,31 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe 'Grape::Endpoint#path_and_definitions' do
4
- before do
5
- module API
6
- module V1
7
- class Item < Grape::API
8
- version 'v1', using: :path
4
+ let(:api) do
5
+ item = Class.new(Grape::API) do
6
+ version 'v1', using: :path
9
7
 
10
- resource :item do
11
- get '/'
12
- end
13
- end
14
- end
15
-
16
- class Root < Grape::API
17
- mount API::V1::Item
18
- add_swagger_documentation add_version: true
8
+ resource :item do
9
+ get '/'
19
10
  end
20
11
  end
21
12
 
22
- @options = { add_version: true }
23
- @target_routes = API::Root.combined_namespace_routes
13
+ Class.new(Grape::API) do
14
+ mount item
15
+ add_swagger_documentation add_version: true
16
+ end
24
17
  end
25
18
 
19
+ let(:options) { { add_version: true } }
20
+ let(:target_routes) { api.combined_namespace_routes }
21
+
22
+ subject { api.endpoints[0].path_and_definition_objects(target_routes, options) }
23
+
26
24
  it 'is returning a versioned path' do
27
- expect(API::V1::Item.endpoints[0]
28
- .path_and_definition_objects(@target_routes, @options)[0].keys[0]).to eql '/v1/item'
25
+ expect(subject[0].keys[0]).to eq '/v1/item'
26
+ end
27
+
28
+ it 'tags the endpoint with the resource name' do
29
+ expect(subject.first['/v1/item'][:get][:tags]).to eq ['item']
29
30
  end
30
31
  end
@@ -21,6 +21,26 @@ describe 'namespace' do
21
21
  end
22
22
  end
23
23
 
24
+ context 'with camel case namespace' do
25
+ def app
26
+ Class.new(Grape::API) do
27
+ namespace :camelCases do
28
+ get '/', desc: 'Look! An endpoint.'
29
+ end
30
+ add_swagger_documentation format: :json
31
+ end
32
+ end
33
+
34
+ subject do
35
+ get '/swagger_doc'
36
+ JSON.parse(last_response.body)['paths']['/camelCases']['get']
37
+ end
38
+
39
+ it 'shows the namespace description in the json spec' do
40
+ expect(subject['description']).to eql('Look! An endpoint.')
41
+ end
42
+ end
43
+
24
44
  context 'mounted' do
25
45
  def app
26
46
  namespaced_api = Class.new(Grape::API) do
@@ -0,0 +1,73 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Params Multi Types' do
4
+ def app
5
+ Class.new(Grape::API) do
6
+ format :json
7
+
8
+ params do
9
+ if Grape::VERSION < '0.14'
10
+ requires :input, type: [String, Integer]
11
+ else
12
+ requires :input, types: [String, Integer]
13
+ end
14
+ requires :another_input, type: [String, Integer]
15
+ end
16
+ post :action do
17
+ end
18
+
19
+ add_swagger_documentation
20
+ end
21
+ end
22
+
23
+ subject do
24
+ get '/swagger_doc/action'
25
+ expect(last_response.status).to eq 200
26
+ body = JSON.parse last_response.body
27
+ body['paths']['/action']['post']['parameters']
28
+ end
29
+
30
+ it 'reads param type correctly' do
31
+ expect(subject).to eq [
32
+ {
33
+ 'in' => 'formData',
34
+ 'name' => 'input',
35
+ 'type' => 'string',
36
+ 'required' => true
37
+ },
38
+ {
39
+ 'in' => 'formData',
40
+ 'name' => 'another_input',
41
+ 'type' => 'string',
42
+ 'required' => true
43
+ }
44
+ ]
45
+ end
46
+
47
+ describe 'header params' do
48
+ def app
49
+ Class.new(Grape::API) do
50
+ format :json
51
+
52
+ desc 'Some API', headers: { 'My-Header' => { required: true, description: 'Set this!' } }
53
+ params do
54
+ if Grape::VERSION < '0.14'
55
+ requires :input, type: [String, Integer]
56
+ else
57
+ requires :input, types: [String, Integer]
58
+ end
59
+ requires :another_input, type: [String, Integer]
60
+ end
61
+ post :action do
62
+ end
63
+
64
+ add_swagger_documentation
65
+ end
66
+ end
67
+
68
+ it 'has consistent types' do
69
+ types = subject.map { |param| param['type'] }
70
+ expect(types).to eq(%w(string string string))
71
+ end
72
+ end
73
+ end
@@ -11,45 +11,72 @@ describe 'Params Types' do
11
11
  post :action do
12
12
  end
13
13
 
14
+ params do
15
+ requires :input, type: String, default: '14', documentation: { type: 'email', default: '42' }
16
+ end
17
+ post :action_with_doc do
18
+ end
19
+
14
20
  add_swagger_documentation
15
21
  end
16
22
  end
23
+ context 'with no documentation hash' do
24
+ subject do
25
+ get '/swagger_doc/action'
26
+ expect(last_response.status).to eq 200
27
+ body = JSON.parse last_response.body
28
+ body['paths']['/action']['post']['parameters']
29
+ end
17
30
 
18
- subject do
19
- get '/swagger_doc/action'
20
- expect(last_response.status).to eq 200
21
- body = JSON.parse last_response.body
22
- body['paths']['/action']['post']['parameters']
23
- end
31
+ it 'reads param type correctly' do
32
+ expect(subject).to eq [{
33
+ 'in' => 'formData',
34
+ 'name' => 'input',
35
+ 'type' => 'string',
36
+ 'required' => true
37
+ }]
38
+ end
24
39
 
25
- it 'reads param type correctly' do
26
- expect(subject).to eq [{
27
- 'in' => 'formData',
28
- 'name' => 'input',
29
- 'type' => 'string',
30
- 'required' => true
31
- }]
32
- end
40
+ describe 'header params' do
41
+ def app
42
+ Class.new(Grape::API) do
43
+ format :json
33
44
 
34
- describe 'header params' do
35
- def app
36
- Class.new(Grape::API) do
37
- format :json
45
+ desc 'Some API', headers: { 'My-Header' => { required: true, description: 'Set this!' } }
46
+ params do
47
+ requires :input, type: String
48
+ end
49
+ post :action do
50
+ end
38
51
 
39
- desc 'Some API', headers: { 'My-Header' => { required: true, description: 'Set this!' } }
40
- params do
41
- requires :input, type: String
42
- end
43
- post :action do
52
+ add_swagger_documentation
44
53
  end
54
+ end
45
55
 
46
- add_swagger_documentation
56
+ it 'has consistent types' do
57
+ types = subject.map { |param| param['type'] }
58
+ expect(types).to eq(%w(string string))
47
59
  end
48
60
  end
61
+ end
62
+
63
+ context 'with documentation hash' do
64
+ subject do
65
+ get '/swagger_doc/action_with_doc'
66
+ expect(last_response.status).to eq 200
67
+ body = JSON.parse last_response.body
68
+ body['paths']['/action_with_doc']['post']['parameters']
69
+ end
49
70
 
50
- it 'has consistent types' do
51
- types = subject.map { |param| param['type'] }
52
- expect(types).to eq(%w(string string))
71
+ it 'reads param type correctly' do
72
+ expect(subject).to eq [{
73
+ 'in' => 'formData',
74
+ 'name' => 'input',
75
+ 'type' => 'string',
76
+ 'format' => 'email',
77
+ 'default' => '42',
78
+ 'required' => true
79
+ }]
53
80
  end
54
81
  end
55
82
  end
@@ -27,6 +27,36 @@ describe 'Group Params as Array' do
27
27
  { 'declared_params' => declared(params) }
28
28
  end
29
29
 
30
+ # as body parameters it would be interpreted a bit different,
31
+ # cause it could not be distinguished anymore, so this would be translated to one array,
32
+ # see also next example for the difference
33
+ params do
34
+ requires :array_of_string, type: Array[String], documentation: { param_type: 'body', desc: 'nested array of strings' }
35
+ requires :array_of_integer, type: Array[Integer], documentation: { param_type: 'body', desc: 'nested array of integers' }
36
+ end
37
+
38
+ post '/array_of_type' do
39
+ { 'declared_params' => declared(params) }
40
+ end
41
+
42
+ params do
43
+ requires :array_of_string, type: Array[String], documentation: { param_type: 'body', desc: 'array of strings' }
44
+ requires :integer_value, type: Integer, documentation: { param_type: 'body', desc: 'integer value' }
45
+ end
46
+
47
+ post '/object_and_array' do
48
+ { 'declared_params' => declared(params) }
49
+ end
50
+
51
+ params do
52
+ requires :array_of_string, type: Array[String]
53
+ requires :array_of_integer, type: Array[Integer]
54
+ end
55
+
56
+ post '/array_of_type_in_form' do
57
+ { 'declared_params' => declared(params) }
58
+ end
59
+
30
60
  add_swagger_documentation
31
61
  end
32
62
  end
@@ -40,8 +70,8 @@ describe 'Group Params as Array' do
40
70
  specify do
41
71
  expect(subject['paths']['/groups']['post']['parameters']).to eql(
42
72
  [
43
- { 'in' => 'formData', 'name' => 'required_group[][required_param_1]', 'required' => true, 'type' => 'array', 'items' => { 'type' => 'string' } },
44
- { 'in' => 'formData', 'name' => 'required_group[][required_param_2]', 'required' => true, 'type' => 'array', 'items' => { 'type' => 'string' } }
73
+ { 'in' => 'formData', 'name' => 'required_group[required_param_1]', 'required' => true, 'type' => 'array', 'items' => { 'type' => 'string' } },
74
+ { 'in' => 'formData', 'name' => 'required_group[required_param_2]', 'required' => true, 'type' => 'array', 'items' => { 'type' => 'string' } }
45
75
  ]
46
76
  )
47
77
  end
@@ -56,10 +86,70 @@ describe 'Group Params as Array' do
56
86
  specify do
57
87
  expect(subject['paths']['/type_given']['post']['parameters']).to eql(
58
88
  [
59
- { 'in' => 'formData', 'name' => 'typed_group[][id]', 'description' => 'integer given', 'required' => true, 'type' => 'array', 'items' => { 'type' => 'integer' } },
60
- { 'in' => 'formData', 'name' => 'typed_group[][name]', 'description' => 'string given', 'required' => true, 'type' => 'array', 'items' => { 'type' => 'string' } },
61
- { 'in' => 'formData', 'name' => 'typed_group[][email]', 'description' => 'email given', 'required' => false, 'type' => 'array', 'items' => { 'type' => 'string' } },
62
- { 'in' => 'formData', 'name' => 'typed_group[][others]', 'required' => false, 'type' => 'array', 'items' => { 'type' => 'integer' }, 'enum' => [1, 2, 3] }
89
+ { 'in' => 'formData', 'name' => 'typed_group[id]', 'description' => 'integer given', 'type' => 'array', 'items' => { 'type' => 'integer', 'format' => 'int32' }, 'required' => true },
90
+ { 'in' => 'formData', 'name' => 'typed_group[name]', 'description' => 'string given', 'type' => 'array', 'items' => { 'type' => 'string' }, 'required' => true },
91
+ { 'in' => 'formData', 'name' => 'typed_group[email]', 'description' => 'email given', 'type' => 'array', 'items' => { 'type' => 'string' }, 'required' => false },
92
+ { 'in' => 'formData', 'name' => 'typed_group[others]', 'type' => 'array', 'items' => { 'type' => 'integer', 'format' => 'int32' }, 'enum' => [1, 2, 3], 'required' => false }
93
+ ]
94
+ )
95
+ end
96
+ end
97
+
98
+ describe 'retrieves the documentation for parameters that are arrays of primitive types' do
99
+ subject do
100
+ get '/swagger_doc/array_of_type'
101
+ JSON.parse(last_response.body)
102
+ end
103
+
104
+ specify do
105
+ expect(subject['definitions']['postArrayOfType']['type']).to eql 'array'
106
+ expect(subject['definitions']['postArrayOfType']['items']).to eql(
107
+ 'type' => 'object',
108
+ 'properties' => {
109
+ 'array_of_string' => {
110
+ 'type' => 'string', 'description' => 'nested array of strings'
111
+ },
112
+ 'array_of_integer' => {
113
+ 'type' => 'integer', 'format' => 'int32', 'description' => 'nested array of integers'
114
+ }
115
+ },
116
+ 'required' => %w(array_of_string array_of_integer)
117
+ )
118
+ end
119
+ end
120
+
121
+ describe 'documentation for simple and array parameters' do
122
+ subject do
123
+ get '/swagger_doc/object_and_array'
124
+ JSON.parse(last_response.body)
125
+ end
126
+
127
+ specify do
128
+ expect(subject['definitions']['postObjectAndArray']['type']).to eql 'object'
129
+ expect(subject['definitions']['postObjectAndArray']['properties']).to eql(
130
+ 'array_of_string' => {
131
+ 'type' => 'array', 'items' => {
132
+ 'type' => 'string', 'description' => 'array of strings'
133
+ }
134
+ },
135
+ 'integer_value' => {
136
+ 'type' => 'integer', 'format' => 'int32', 'description' => 'integer value'
137
+ }
138
+ )
139
+ end
140
+ end
141
+
142
+ describe 'retrieves the documentation for typed group parameters' do
143
+ subject do
144
+ get '/swagger_doc/array_of_type_in_form'
145
+ JSON.parse(last_response.body)
146
+ end
147
+
148
+ specify do
149
+ expect(subject['paths']['/array_of_type_in_form']['post']['parameters']).to eql(
150
+ [
151
+ { 'in' => 'formData', 'name' => 'array_of_string', 'type' => 'array', 'items' => { 'type' => 'string' }, 'required' => true },
152
+ { 'in' => 'formData', 'name' => 'array_of_integer', 'type' => 'array', 'items' => { 'type' => 'integer', 'format' => 'int32' }, 'required' => true }
63
153
  ]
64
154
  )
65
155
  end