From eb0d85d1786ca1cb516c4fc277e128fa3e114df3 Mon Sep 17 00:00:00 2001 From: Josh Murphy Date: Thu, 19 Jul 2018 10:28:25 -0500 Subject: [PATCH] Fix array of entities with nested entities (#683) * Update prepare_nested_types to allow for references and update specs * Add CHANGELOG entry * Fix lint --- CHANGELOG.md | 2 +- lib/grape-swagger/doc_methods/move_params.rb | 11 +- spec/lib/move_params_spec.rb | 188 +++++++++++++++++++ 3 files changed, 198 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e95d148f..7ffde049 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ #### Fixes -* Your contribution here. +* [#683](https://github.com/ruby-grape/grape-swagger/pull/683): Fix handling of arrays of complex entities in params so that valid OpenAPI spec is generated - [@jdmurphy](https://github.com/jdmurphy). ### 0.29.0 (May 22, 2018) diff --git a/lib/grape-swagger/doc_methods/move_params.rb b/lib/grape-swagger/doc_methods/move_params.rb index 2a8c36c5..a73005b8 100644 --- a/lib/grape-swagger/doc_methods/move_params.rb +++ b/lib/grape-swagger/doc_methods/move_params.rb @@ -177,9 +177,16 @@ def object_type def prepare_nested_types(params) params.each do |param| next unless param[:items] - param[:type] = param[:items][:type] == 'array' ? 'string' : param[:items][:type] + + param[:type] = if param[:items][:type] == 'array' + 'string' + elsif param[:items].key?('$ref') + param[:type] = 'object' + else + param[:items][:type] + end param[:format] = param[:items][:format] if param[:items][:format] - param.delete(:items) + param.delete(:items) if param[:type] != 'object' end end diff --git a/spec/lib/move_params_spec.rb b/spec/lib/move_params_spec.rb index 92bf06cc..2d020b50 100644 --- a/spec/lib/move_params_spec.rb +++ b/spec/lib/move_params_spec.rb @@ -325,5 +325,193 @@ it { expect(params).to eql expected_params } end end + + describe 'prepare_nested_types' do + before :each do + subject.send(:prepare_nested_types, params) + end + + let(:params) do + [ + { + in: 'body', + name: 'address[street_lines]', + description: 'street lines', + type: 'array', + items: { + type: 'string' + }, + required: true + } + ] + end + + context 'when params contains nothing with :items key' do + let(:params) do + [ + { + in: 'body', + name: 'phone_number', + description: 'phone number', + type: 'string', + required: true + } + ] + end + + let(:expected_params) do + [ + { + in: 'body', + name: 'phone_number', + description: 'phone number', + type: 'string', + required: true + } + ] + end + + it 'does nothing' do + expect(params).to eq expected_params + end + end + + context 'when params contains :items key with array type' do + let(:params) do + [ + { + in: 'body', + name: 'address_street_lines', + description: 'street lines', + type: 'array', + items: { + type: 'array' + }, + required: true + } + ] + end + + let(:expected_params) do + [ + { + in: 'body', + name: 'address_street_lines', + description: 'street lines', + type: 'string', + required: true + } + ] + end + + it 'sets type to string and removes :items' do + expect(params).to eq expected_params + end + end + + context 'when params contains :items key with $ref' do + let(:params) do + [ + { + in: 'body', + name: 'address_street_lines', + description: 'street lines', + type: 'array', + items: { + '$ref' => '#/definitions/StreetLine' + }, + required: true + } + ] + end + + let(:expected_params) do + [ + { + in: 'body', + name: 'address_street_lines', + description: 'street lines', + type: 'object', + items: { + '$ref' => '#/definitions/StreetLine' + }, + required: true + } + ] + end + + it 'sets type to object and does not remove :items' do + expect(params).to eq expected_params + end + end + + context 'when params contains :items without $ref or array type' do + let(:params) do + [ + { + in: 'body', + name: 'address_street_lines', + description: 'street lines', + type: 'array', + items: { + type: 'string' + }, + required: true + } + ] + end + + let(:expected_params) do + [ + { + in: 'body', + name: 'address_street_lines', + description: 'street lines', + type: 'string', + required: true + } + ] + end + + it 'sets type to :items :type and removes :items' do + expect(params).to eq expected_params + end + end + + context 'when params contains :items key with :format' do + let(:params) do + [ + { + in: 'body', + name: 'street_number', + description: 'street number', + type: 'array', + items: { + type: 'integer', + format: 'int32' + }, + required: true + } + ] + end + + let(:expected_params) do + [ + { + in: 'body', + name: 'street_number', + description: 'street number', + type: 'integer', + format: 'int32', + required: true + } + ] + end + + it 'sets format and removes :items' do + expect(params).to eq expected_params + end + end + end end end