From 1b818622a0f72ffc0d10c6f36b4049504f46d68a Mon Sep 17 00:00:00 2001 From: diachini Date: Tue, 19 May 2020 10:23:20 -0400 Subject: [PATCH] Allow OpenAPI 3.0 array query parameter schema (#317) In OpenAPI 3.0, a query parameter can be specified like: ``` name: id in: query schema: type: array items: type: string ``` see: https://swagger.io/specification/#parameter-object In order to support generating the correct OpenAPI 3.0 specification and to still allow rswag specs to pass, this checks to see if `array` is specified in the `type` of the parameter, or if it's specified in the `schema: { type:` instead. re: #317 --- .../lib/rswag/specs/request_factory.rb | 15 ++++-- .../spec/rswag/specs/request_factory_spec.rb | 46 +++++++++++++++++++ 2 files changed, 58 insertions(+), 3 deletions(-) diff --git a/rswag-specs/lib/rswag/specs/request_factory.rb b/rswag-specs/lib/rswag/specs/request_factory.rb index 2e8f3f1da..d9622680f 100644 --- a/rswag-specs/lib/rswag/specs/request_factory.rb +++ b/rswag-specs/lib/rswag/specs/request_factory.rb @@ -111,14 +111,23 @@ def add_path(request, metadata, swagger_doc, parameters, example) parameters.select { |p| p[:in] == :query }.each_with_index do |p, i| path_template.concat(i.zero? ? '?' : '&') - path_template.concat(build_query_string_part(p, example.send(p[:name]))) + path_template.concat(build_query_string_part(p, example.send(p[:name]), swagger_doc)) end end end - def build_query_string_part(param, value) + def param_is_array?(param) + param[:type]&.to_sym == :array || param.dig(:schema, :type)&.to_sym == :array + end + + def build_query_string_part(param, value, swagger_doc) name = param[:name] - return "#{name}=#{value}" unless param[:type].to_sym == :array + + if doc_version(swagger_doc).start_with?('2') + return "#{name}=#{value}" unless param[:type].to_sym == :array + else # Openapi3 + return "#{name}=#{value}" unless param_is_array?(param) + end case param[:collectionFormat] when :ssv diff --git a/rswag-specs/spec/rswag/specs/request_factory_spec.rb b/rswag-specs/spec/rswag/specs/request_factory_spec.rb index aff5fb4eb..89e961156 100644 --- a/rswag-specs/spec/rswag/specs/request_factory_spec.rb +++ b/rswag-specs/spec/rswag/specs/request_factory_spec.rb @@ -103,6 +103,52 @@ module Specs end end + context "'query' parameters of type 'array' by way of 'schema'" do + let(:swagger_doc) { { swagger: '3.0.3' } } + + before do + metadata[:operation][:parameters] = [ + { name: 'things', in: :query, schema: { type: :array }, collectionFormat: collection_format } + ] + allow(example).to receive(:things).and_return(['foo', 'bar']) + end + + context 'collectionFormat = csv' do + let(:collection_format) { :csv } + it 'formats as comma separated values' do + expect(request[:path]).to eq('/blogs?things=foo,bar') + end + end + + context 'collectionFormat = ssv' do + let(:collection_format) { :ssv } + it 'formats as space separated values' do + expect(request[:path]).to eq('/blogs?things=foo bar') + end + end + + context 'collectionFormat = tsv' do + let(:collection_format) { :tsv } + it 'formats as tab separated values' do + expect(request[:path]).to eq('/blogs?things=foo\tbar') + end + end + + context 'collectionFormat = pipes' do + let(:collection_format) { :pipes } + it 'formats as pipe separated values' do + expect(request[:path]).to eq('/blogs?things=foo|bar') + end + end + + context 'collectionFormat = multi' do + let(:collection_format) { :multi } + it 'formats as multiple parameter instances' do + expect(request[:path]).to eq('/blogs?things=foo&things=bar') + end + end + end + context "'header' parameters" do before do metadata[:operation][:parameters] = [{ name: 'Api-Key', in: :header, type: :string }]