Skip to content

Commit 756feb5

Browse files
author
peter scholz
authored
fixes body array params (#464)
- adds chengelog entry
1 parent 60782ea commit 756feb5

10 files changed

+87
-51
lines changed

.rubocop.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
AllCops:
22
Exclude:
33
- vendor/**/*
4+
- example/**/*
45

56
inherit_from: .rubocop_todo.yml

CHANGELOG.md

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

1010
#### Fixes
1111

12+
* [#464](https://github.com/ruby-grape/grape-swagger/pull/464): Fixes array params, sets correct type and format for items - [@LeFnord](https://github.com/LeFnord).
1213
* [#461](https://github.com/ruby-grape/grape-swagger/pull/461): Fixes issue by adding extensions to definitions. It appeared, if for the given status code, no definition could be found - [@LeFnord](https://github.com/LeFnord).
1314
* [#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).
1415
* [#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).

example/api/endpoints.rb

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -23,21 +23,21 @@ class Splines < Grape::API
2323
namespace :splines do
2424
#
2525
desc 'Get all splines',
26-
is_array: true,
27-
http_codes: [
28-
{ code: 200, message: 'get Splines', model: Api::Entities::Splines },
29-
{ code: 422, message: 'SplinesOutError' }
30-
]
26+
is_array: true,
27+
http_codes: [
28+
{ code: 200, message: 'get Splines', model: Api::Entities::Splines },
29+
{ code: 422, message: 'SplinesOutError' }
30+
]
3131
get do
3232
present :items, @@splines, with: Entities::Splines
3333
end
3434

3535
#
3636
desc 'Return a spline.',
37-
http_codes: [
38-
{ code: 200, message: 'get Splines' },
39-
{ code: 422, message: 'SplinesOutError' }
40-
]
37+
http_codes: [
38+
{ code: 200, message: 'get Splines' },
39+
{ code: 422, message: 'SplinesOutError' }
40+
]
4141
params do
4242
requires :id, type: Integer, desc: 'Spline id.'
4343
end
@@ -49,9 +49,9 @@ class Splines < Grape::API
4949

5050
#
5151
desc 'Create a spline.',
52-
http_codes: [
53-
{ code: 201, message: 'Spline created', model: Api::Entities::Splines }
54-
]
52+
http_codes: [
53+
{ code: 201, message: 'Spline created', model: Api::Entities::Splines }
54+
]
5555
params do
5656
requires :spline, type: Hash do
5757
requires :x, type: Numeric
@@ -73,10 +73,10 @@ class Splines < Grape::API
7373

7474
#
7575
desc 'Update a spline.',
76-
http_codes: [
77-
{ code: 200, message: 'update Splines', model: Api::Entities::Splines },
78-
{ code: 422, message: 'SplinesOutError' }
79-
]
76+
http_codes: [
77+
{ code: 200, message: 'update Splines', model: Api::Entities::Splines },
78+
{ code: 422, message: 'SplinesOutError' }
79+
]
8080
params do
8181
requires :id, type: Integer, desc: 'Spline id.'
8282
optional :spline, type: Hash do

lib/grape-swagger/doc_methods/move_params.rb

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,13 @@ def nested_definitions(name, params, properties)
8383
nested.each { |x| params.delete(x) }
8484
nested_def_name = GrapeSwagger::DocMethods::OperationId.manipulate(nested_name)
8585
def_name = "#{name}#{nested_def_name}"
86-
properties[nested_name] = { '$ref' => "#/definitions/#{def_name}" }
8786

87+
if nested.first[:type] && nested.first[:type] == 'array'
88+
prepare_nested_types(nested)
89+
properties[nested_name] = { type: 'array', items: { '$ref' => "#/definitions/#{def_name}" } }
90+
else
91+
properties[nested_name] = { '$ref' => "#/definitions/#{def_name}" }
92+
end
8893
prepare_nested_names(nested)
8994
build_definition(def_name)
9095
@definitions[def_name][:description] = "#{name} - #{nested_name}"
@@ -113,13 +118,20 @@ def build_definition(name, verb = nil)
113118
name
114119
end
115120

121+
def prepare_nested_types(params)
122+
params.each do |param|
123+
next unless param[:items]
124+
param[:type] = param[:items][:type]
125+
param[:format] = param[:items][:format] if param[:items][:format]
126+
param.delete(:items)
127+
end
128+
end
129+
116130
def prepare_nested_names(params)
117131
params.each do |param|
118-
param.tap do |x|
119-
name = x[:name].partition('[').last.sub(']', '')
120-
name = name.partition('[').last.sub(']', '') if name.start_with?('[')
121-
x[:name] = name
122-
end
132+
name = param[:name].partition('[').last.sub(']', '')
133+
name = name.partition('[').last.sub(']', '') if name.start_with?('[')
134+
param[:name] = name
123135
end
124136
end
125137

@@ -145,10 +157,7 @@ def property_keys
145157
def movable?(param)
146158
param[:in] == 'body'
147159
end
148-
149-
def deletable?(param)
150-
param[:in] == 'body'
151-
end
160+
alias deletable? movable?
152161

153162
def should_move?(params)
154163
!params.select { |x| x[:in] == 'body' || x[:param_type] == 'body' }.empty?

lib/grape-swagger/doc_methods/parse_params.rb

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,14 +65,17 @@ def document_array_param(value_type)
6565
if value_type[:documentation].present?
6666
param_type = value_type[:documentation][:param_type]
6767
doc_type = value_type[:documentation][:type]
68-
type = GrapeSwagger::DocMethods::DataType.mapping(doc_type) if doc_type
68+
type = GrapeSwagger::DocMethods::DataType.mapping(doc_type) if doc_type && !DataType.request_primitive?(doc_type)
6969
end
70-
array_items = { 'type' => type || value_type[:data_type] }
70+
71+
array_items = {
72+
type: type || @parsed_param[:type],
73+
format: @parsed_param.delete(:format)
74+
}.delete_if { |_, value| value.blank? }
7175

7276
@parsed_param[:in] = param_type || 'formData'
7377
@parsed_param[:items] = array_items
7478
@parsed_param[:type] = 'array'
75-
@parsed_param.delete(:format)
7679
end
7780
end
7881

spec/lib/move_params_spec.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,8 @@
107107
end
108108

109109
describe 'array' do
110-
let(:params) { [{ in: 'body', name: 'address[][street_lines]', description: 'street lines', type: 'array', required: true }] }
111-
let(:expected) { [{ in: 'body', name: 'street_lines', description: 'street lines', type: 'array', required: true }] }
110+
let(:params) { [{ in: 'body', name: 'address[street_lines]', description: 'street lines', type: 'array', items: { type: 'string' }, required: true }] }
111+
let(:expected) { [{ in: 'body', name: 'street_lines', description: 'street lines', type: 'array', items: { type: 'string' }, required: true }] }
112112
specify do
113113
expect(params).to eql expected
114114
end

spec/swagger_v2/api_swagger_v2_param_type_body_nested_spec.rb

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
require 'spec_helper'
22

3-
describe 'setting of param type, such as `query`, `path`, `formData`, `body`, `header`' do
3+
describe 'moving body/formData Params to definitions' do
44
include_context "#{MODEL_PARSER} swagger example"
55

66
before :all do
@@ -12,7 +12,7 @@ class NestedBodyParamTypeApi < Grape::API
1212
success: Entities::UseNestedWithAddress
1313
params do
1414
requires :name, type: String, documentation: { desc: 'name', in: 'body' }
15-
optional :address, type: Hash do
15+
optional :addresses, type: Array do
1616
requires :street, type: String, documentation: { desc: 'street', in: 'body' }
1717
requires :postcode, type: String, documentation: { desc: 'postcode', in: 'body' }
1818
requires :city, type: String, documentation: { desc: 'city', in: 'body' }
@@ -44,6 +44,28 @@ class NestedBodyParamTypeApi < Grape::API
4444
end
4545

4646
namespace :multiple_nested_params do
47+
desc 'put in body with multiple nested parameters',
48+
success: Entities::UseNestedWithAddress
49+
params do
50+
optional :name, type: String, documentation: { desc: 'name', in: 'body' }
51+
optional :addresses, type: Array do
52+
optional :street, type: String, documentation: { desc: 'street', in: 'body' }
53+
requires :postcode, type: String, documentation: { desc: 'postcode', in: 'formData' }
54+
optional :city, type: String, documentation: { desc: 'city', in: 'body' }
55+
optional :country, type: String, documentation: { desc: 'country', in: 'body' }
56+
end
57+
optional :delivery_address, type: Hash do
58+
optional :street, type: String, documentation: { desc: 'street', in: 'body' }
59+
optional :postcode, type: String, documentation: { desc: 'postcode', in: 'formData' }
60+
optional :city, type: String, documentation: { desc: 'city', in: 'body' }
61+
optional :country, type: String, documentation: { desc: 'country', in: 'body' }
62+
end
63+
end
64+
65+
post '/in_body' do
66+
{ 'declared_params' => declared(params) }
67+
end
68+
4769
desc 'put in body with multiple nested parameters',
4870
success: Entities::UseNestedWithAddress
4971
params do
@@ -96,24 +118,24 @@ def app
96118

97119
specify do
98120
expect(subject['definitions']['postRequestUseNestedWithAddress']).to eql(
99-
'description' => "post in body with nested parameters\n more details description",
100121
'type' => 'object',
101122
'properties' => {
102-
'address' => { '$ref' => '#/definitions/postRequestUseNestedWithAddressAddress' },
123+
'addresses' => { 'type' => 'array', 'items' => { '$ref' => '#/definitions/postRequestUseNestedWithAddressAddresses' } },
103124
'name' => { 'type' => 'string', 'description' => 'name' }
104125
},
105-
'required' => ['name']
126+
'required' => ['name'],
127+
'description' => "post in body with nested parameters\n more details description"
106128
)
107-
expect(subject['definitions']['postRequestUseNestedWithAddressAddress']).to eql(
108-
'description' => 'postRequestUseNestedWithAddress - address',
129+
expect(subject['definitions']['postRequestUseNestedWithAddressAddresses']).to eql(
109130
'type' => 'object',
110131
'properties' => {
111132
'street' => { 'type' => 'string', 'description' => 'street' },
112133
'postcode' => { 'type' => 'string', 'description' => 'postcode' },
113134
'city' => { 'type' => 'string', 'description' => 'city' },
114135
'country' => { 'type' => 'string', 'description' => 'country' }
115136
},
116-
'required' => %w(street postcode city)
137+
'required' => %w(street postcode city),
138+
'description' => 'postRequestUseNestedWithAddress - addresses'
117139
)
118140
end
119141

spec/swagger_v2/api_swagger_v2_response_spec.rb

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ class ResponseApi < Grape::API
1111
desc 'This returns something',
1212
params: Entities::UseResponse.documentation,
1313
failure: [{ code: 400, message: 'NotFound', model: Entities::ApiError }]
14-
post '/params_response' do
14+
post '/params_given' do
1515
{ 'declared_params' => declared(params) }
1616
end
1717

@@ -83,12 +83,12 @@ def app
8383

8484
describe 'uses params as response object' do
8585
subject do
86-
get '/swagger_doc/params_response'
86+
get '/swagger_doc/params_given'
8787
JSON.parse(last_response.body)
8888
end
8989

9090
specify do
91-
expect(subject['paths']['/params_response']['post']).to eql(
91+
expect(subject['paths']['/params_given']['post']).to eql(
9292
'summary' => 'This returns something',
9393
'description' => 'This returns something',
9494
'produces' => ['application/json'],
@@ -101,8 +101,8 @@ def app
101101
'201' => { 'description' => 'This returns something' },
102102
'400' => { 'description' => 'NotFound', 'schema' => { '$ref' => '#/definitions/ApiError' } }
103103
},
104-
'tags' => ['params_response'],
105-
'operationId' => 'postParamsResponse'
104+
'tags' => ['params_given'],
105+
'operationId' => 'postParamsGiven'
106106
)
107107
expect(subject['definitions']).to eql(swagger_params_as_response_object)
108108
end

spec/swagger_v2/params_array_spec.rb

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -74,10 +74,10 @@ def app
7474
specify do
7575
expect(subject['paths']['/type_given']['post']['parameters']).to eql(
7676
[
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] }
77+
{ 'in' => 'formData', 'name' => 'typed_group[id]', 'description' => 'integer given', 'type' => 'array', 'items' => { 'type' => 'integer', 'format' => 'int32' }, 'required' => true },
78+
{ 'in' => 'formData', 'name' => 'typed_group[name]', 'description' => 'string given', 'type' => 'array', 'items' => { 'type' => 'string' }, 'required' => true },
79+
{ 'in' => 'formData', 'name' => 'typed_group[email]', 'description' => 'email given', 'type' => 'array', 'items' => { 'type' => 'string' }, 'required' => false },
80+
{ 'in' => 'formData', 'name' => 'typed_group[others]', 'type' => 'array', 'items' => { 'type' => 'integer', 'format' => 'int32' }, 'enum' => [1, 2, 3], 'required' => false }
8181
]
8282
)
8383
end
@@ -95,7 +95,7 @@ def app
9595
'type' => 'array', 'items' => { 'type' => 'string' }, 'description' => 'nested array of strings'
9696
},
9797
'array_of_integer' => {
98-
'type' => 'array', 'items' => { 'type' => 'integer' }, 'description' => 'nested array of integers'
98+
'type' => 'array', 'items' => { 'type' => 'integer', 'format' => 'int32' }, 'description' => 'nested array of integers'
9999
}
100100
)
101101
end
@@ -111,7 +111,7 @@ def app
111111
expect(subject['paths']['/array_of_type_in_form']['post']['parameters']).to eql(
112112
[
113113
{ '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 }
114+
{ 'in' => 'formData', 'name' => 'array_of_integer', 'type' => 'array', 'items' => { 'type' => 'integer', 'format' => 'int32' }, 'required' => true }
115115
]
116116
)
117117
end

spec/swagger_v2/params_nested_spec.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ 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' } },
45+
{ 'in' => 'formData', 'name' => 'a_array[param_1]', 'required' => true, 'type' => 'array', 'items' => { 'type' => 'integer', 'format' => 'int32' } },
4646
{ 'in' => 'formData', 'name' => 'a_array[b_array][param_2]', 'required' => true, 'type' => 'array', 'items' => { 'type' => 'string' } }
4747
]
4848
)

0 commit comments

Comments
 (0)