Skip to content

Commit a07385f

Browse files
TySpringdblock
authored andcommitted
Allow passing of Array with brackets (eg. Array[String], Array[Integer]) (#455)
1 parent 4e2c235 commit a07385f

10 files changed

+128
-20
lines changed

.rubocop_todo.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ Metrics/AbcSize:
2828
# Offense count: 3
2929
# Configuration parameters: CountComments.
3030
Metrics/ClassLength:
31-
Max: 206
31+
Max: 209
3232

3333
# Offense count: 10
3434
Metrics/CyclomaticComplexity:

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#### Fixes
1010

11+
* [#455](https://github.com/ruby-grape/grape-swagger/pull/455): Setting `type:` option as `Array[Class]` creates `array` type in JSON - [@tyspring](https://github.com/tyspring).
1112
* [#450](https://github.com/ruby-grape/grape-swagger/pull/438): Do not add :description to definitions if :description is missing on path - [@texpert](https://github.com/texpert).
1213
* [#447](https://github.com/ruby-grape/grape-swagger/pull/447): Version part of the url is now ignored when generating tags for endpoint - [@anakinj](https://github.com/anakinj).
1314
* [#444](https://github.com/ruby-grape/grape-swagger//pull/444): Default value provided in the documentation hash, override the grape default [@scauglog](https://github.com/scauglog).

README.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,30 @@ end
481481
}
482482
```
483483
484+
#### Array type
485+
486+
Array types are also supported.
487+
488+
```ruby
489+
params do
490+
requires :action_ids, type: Array[Integer]
491+
end
492+
post :act do
493+
...
494+
end
495+
```
496+
497+
```json
498+
{
499+
"in": "formData",
500+
"name": "action_ids",
501+
"type": "array",
502+
"items": {
503+
"type": "integer"
504+
},
505+
"required": true
506+
}
507+
```
484508
485509
#### Multi types
486510

lib/grape-swagger/doc_methods/parse_params.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@ def document_array_param(value_type)
6464
if value_type[:is_array]
6565
if value_type[:documentation].present?
6666
param_type = value_type[:documentation][:param_type]
67-
type = GrapeSwagger::DocMethods::DataType.mapping(value_type[:documentation][:type])
67+
doc_type = value_type[:documentation][:type]
68+
type = GrapeSwagger::DocMethods::DataType.mapping(doc_type) if doc_type
6869
end
6970
array_items = { 'type' => type || value_type[:data_type] }
7071

lib/grape-swagger/endpoint.rb

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -222,19 +222,24 @@ def default_type(params)
222222
end
223223

224224
def parse_request_params(required)
225+
array_key = nil
225226
required.each_with_object({}) do |param, memo|
226-
@array_key = param.first.to_s.gsub('[', '[][') if param.last[:type] == 'Array'
227-
possible_key = param.first.to_s.gsub('[', '[][')
228-
if @array_key && possible_key.start_with?(@array_key)
229-
key = possible_key
230-
param.last[:is_array] = true
231-
else
232-
key = param.first
233-
end
234-
memo[key] = param.last unless (param.last[:type] == 'Hash' || param.last[:type] == 'Array') && !param.last.key?(:documentation)
227+
array_key = param.first.to_s if param_type_is_array?(param.last[:type])
228+
229+
param.last[:is_array] = true if array_key && param.first.start_with?(array_key)
230+
memo[param.first] = param.last unless (param.last[:type] == 'Hash' || param.last[:type] == 'Array') && !param.last.key?(:documentation)
235231
end
236232
end
237233

234+
def param_type_is_array?(param_type)
235+
return false unless param_type
236+
return true if param_type == 'Array'
237+
param_types = param_type.match(/\[(.*)\]$/)
238+
return false unless param_types
239+
param_types = param_types[0].split(',') if param_types
240+
param_types.size == 1
241+
end
242+
238243
def expose_params_from_model(model)
239244
model_name = model_name(model)
240245

spec/lib/data_type_spec.rb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,4 +65,16 @@
6565

6666
it { expect(subject).to eql 'string' }
6767
end
68+
69+
describe '[String]' do
70+
let(:value) { { type: '[String]' } }
71+
72+
it { expect(subject).to eq('string') }
73+
end
74+
75+
describe '[Integer]' do
76+
let(:value) { { type: '[Integer]' } }
77+
78+
it { expect(subject).to eq('integer') }
79+
end
6880
end

spec/lib/endpoint_spec.rb

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,17 @@
22

33
describe Grape::Endpoint do
44
subject { described_class.new(Grape::Util::InheritableSetting.new, path: '/', method: :get) }
5+
6+
describe '#param_type_is_array?' do
7+
it 'returns true if the value passed represents an array' do
8+
expect(subject.send(:param_type_is_array?, 'Array')).to be_truthy
9+
expect(subject.send(:param_type_is_array?, '[String]')).to be_truthy
10+
expect(subject.send(:param_type_is_array?, 'Array[Integer]')).to be_truthy
11+
end
12+
13+
it 'returns false if the value passed does not represent an array' do
14+
expect(subject.send(:param_type_is_array?, 'String')).to be_falsey
15+
expect(subject.send(:param_type_is_array?, '[String, Integer]')).to be_falsey
16+
end
17+
end
518
end

spec/swagger_v2/api_swagger_v2_detail_spec.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ def app
144144
specify do
145145
expect(subject['paths']['/use_gfm_rc_detail']['get']).to include('description')
146146
expect(subject['paths']['/use_gfm_rc_detail']['get']['description']).to eql(
147-
"<h1>This returns something</h1>\n\n<p># Burgers in Heaven</p>\n\n<blockquote>\n<p>A burger doesn&#39;t come for free</p>\n</blockquote>\n\n<p>If you want to reserve a burger in heaven, you have to do\nsome crazy stuff on earth.</p>\n<pre class=\"highlight plaintext\"><code>def do_good\nputs 'help people'\nend\n</code></pre>\n<ul>\n<li><em>Will go to Heaven:</em> Probably</li>\n<li><em>Will go to Hell:</em> Probably not</li>\n</ul>"
147+
"<h1>This returns something</h1>\n\n<p># Burgers in Heaven</p>\n\n<blockquote>\n<p>A burger doesn&#39;t come for free</p>\n</blockquote>\n\n<p>If you want to reserve a burger in heaven, you have to do\nsome crazy stuff on earth.</p>\n<pre class=\"highlight plaintext\"><code>def do_good\nputs 'help people'\nend\n</code></pre>\n\n<ul>\n<li><em>Will go to Heaven:</em> Probably</li>\n<li><em>Will go to Hell:</em> Probably not</li>\n</ul>"
148148
)
149149
end
150150
end

spec/swagger_v2/params_array_spec.rb

Lines changed: 58 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,24 @@ def app
2727
{ 'declared_params' => declared(params) }
2828
end
2929

30+
params do
31+
requires :array_of_string, type: Array[String], documentation: { param_type: 'body', desc: 'nested array of strings' }
32+
requires :array_of_integer, type: Array[Integer], documentation: { param_type: 'body', desc: 'nested array of integers' }
33+
end
34+
35+
post '/array_of_type' do
36+
{ 'declared_params' => declared(params) }
37+
end
38+
39+
params do
40+
requires :array_of_string, type: Array[String]
41+
requires :array_of_integer, type: Array[Integer]
42+
end
43+
44+
post '/array_of_type_in_form' do
45+
{ 'declared_params' => declared(params) }
46+
end
47+
3048
add_swagger_documentation
3149
end
3250
end
@@ -40,8 +58,8 @@ def app
4058
specify do
4159
expect(subject['paths']['/groups']['post']['parameters']).to eql(
4260
[
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' } }
61+
{ 'in' => 'formData', 'name' => 'required_group[required_param_1]', 'required' => true, 'type' => 'array', 'items' => { 'type' => 'string' } },
62+
{ 'in' => 'formData', 'name' => 'required_group[required_param_2]', 'required' => true, 'type' => 'array', 'items' => { 'type' => 'string' } }
4563
]
4664
)
4765
end
@@ -56,10 +74,44 @@ def app
5674
specify do
5775
expect(subject['paths']['/type_given']['post']['parameters']).to eql(
5876
[
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] }
77+
{ 'in' => 'formData', 'name' => 'typed_group[id]', 'description' => 'integer given', 'required' => true, 'type' => 'array', 'items' => { 'type' => 'integer' } },
78+
{ 'in' => 'formData', 'name' => 'typed_group[name]', 'description' => 'string given', 'required' => true, 'type' => 'array', 'items' => { 'type' => 'string' } },
79+
{ 'in' => 'formData', 'name' => 'typed_group[email]', 'description' => 'email given', 'required' => false, 'type' => 'array', 'items' => { 'type' => 'string' } },
80+
{ 'in' => 'formData', 'name' => 'typed_group[others]', 'required' => false, 'type' => 'array', 'items' => { 'type' => 'integer' }, 'enum' => [1, 2, 3] }
81+
]
82+
)
83+
end
84+
end
85+
86+
describe 'retrieves the documentation for parameters that are arrays of primitive types' do
87+
subject do
88+
get '/swagger_doc/array_of_type'
89+
JSON.parse(last_response.body)
90+
end
91+
92+
specify do
93+
expect(subject['definitions']['postArrayOfType']['properties']).to eql(
94+
'array_of_string' => {
95+
'type' => 'array', 'items' => { 'type' => 'string' }, 'description' => 'nested array of strings'
96+
},
97+
'array_of_integer' => {
98+
'type' => 'array', 'items' => { 'type' => 'integer' }, 'description' => 'nested array of integers'
99+
}
100+
)
101+
end
102+
end
103+
104+
describe 'retrieves the documentation for typed group parameters' do
105+
subject do
106+
get '/swagger_doc/array_of_type_in_form'
107+
JSON.parse(last_response.body)
108+
end
109+
110+
specify do
111+
expect(subject['paths']['/array_of_type_in_form']['post']['parameters']).to eql(
112+
[
113+
{ 'in' => 'formData', 'name' => 'array_of_string', 'type' => 'array', 'items' => { 'type' => 'string' }, 'required' => true },
114+
{ 'in' => 'formData', 'name' => 'array_of_integer', 'type' => 'array', 'items' => { 'type' => 'integer' }, 'required' => true }
63115
]
64116
)
65117
end

spec/swagger_v2/params_nested_spec.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@ def app
4242
specify do
4343
expect(subject['paths']['/nested_array']['post']['parameters']).to eql(
4444
[
45-
{ 'in' => 'formData', 'name' => 'a_array[][param_1]', 'required' => true, 'type' => 'array', 'items' => { 'type' => 'integer' } },
46-
{ 'in' => 'formData', 'name' => 'a_array[][b_array][][param_2]', 'required' => true, 'type' => 'array', 'items' => { 'type' => 'string' } }
45+
{ 'in' => 'formData', 'name' => 'a_array[param_1]', 'required' => true, 'type' => 'array', 'items' => { 'type' => 'integer' } },
46+
{ 'in' => 'formData', 'name' => 'a_array[b_array][param_2]', 'required' => true, 'type' => 'array', 'items' => { 'type' => 'string' } }
4747
]
4848
)
4949
end

0 commit comments

Comments
 (0)