diff --git a/CHANGELOG.md b/CHANGELOG.md index b98063cc..adb6665a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ * [#954](https://github.com/ruby-grape/grape-swagger/pull/954): Ruby 3.5 compatibility: add cgi gem, drop runtime `rack‑test` - [@numbata](https://github.com/numbata). * [#948](https://github.com/ruby-grape/grape-swagger/pull/948): Grape 2.3.0 and Ruby 3.5 compatibility - [@numbata](https://github.com/numbata). +* [#957](https://github.com/ruby-grape/grape-swagger/pull/957): Fix issue where array params are sometimes omitted when `array_use_braces` is true - [@olivier-thatch](https://github.com/olivier-thatch). * Your contribution here. ### 2.1.2 (2025-01-07) diff --git a/lib/grape-swagger/doc_methods/move_params.rb b/lib/grape-swagger/doc_methods/move_params.rb index c8417ce5..12c64778 100644 --- a/lib/grape-swagger/doc_methods/move_params.rb +++ b/lib/grape-swagger/doc_methods/move_params.rb @@ -136,7 +136,7 @@ def add_to_required(definition, value) return if value.blank? definition[:required] ||= [] - definition[:required].push(*value) + definition[:required].push(*value).uniq! end def build_body_parameter(name, options) diff --git a/lib/grape-swagger/doc_methods/parse_params.rb b/lib/grape-swagger/doc_methods/parse_params.rb index 7e7c0c8c..b1c3a842 100644 --- a/lib/grape-swagger/doc_methods/parse_params.rb +++ b/lib/grape-swagger/doc_methods/parse_params.rb @@ -17,6 +17,7 @@ def call(param, settings, path, route, definitions, consumes) # rubocop:disable in: param_type(value_type, consumes), name: settings[:full_name] || param } + fix_name_of_body_array_param(value_type) # optional properties document_description(settings) @@ -35,6 +36,12 @@ def call(param, settings, path, route, definitions, consumes) # rubocop:disable private + def fix_name_of_body_array_param(value_type) + return unless @parsed_param[:in] == 'body' && value_type[:is_array] + + @parsed_param[:name] = @parsed_param[:name].delete_suffix('[]') + end + def document_description(settings) description = settings[:desc] || settings[:description] @parsed_param[:description] = description if description diff --git a/spec/swagger_v2/params_array_spec.rb b/spec/swagger_v2/params_array_spec.rb index 510309b2..331dd930 100644 --- a/spec/swagger_v2/params_array_spec.rb +++ b/spec/swagger_v2/params_array_spec.rb @@ -95,6 +95,27 @@ { 'declared_params' => declared(params) } end + helpers do + params :common_params do + requires :array_of_string, type: Array[String] + requires :array_of_integer, type: Array[Integer] + end + end + + params do + use :common_params + end + get '/endpoint_with_common_params' do + { 'declared_params' => declared(params) } + end + + params do + use :common_params + end + post '/endpoint_with_common_params' do + { 'declared_params' => declared(params) } + end + add_swagger_documentation array_use_braces: array_use_braces end end @@ -220,6 +241,53 @@ expect(subject['paths']['/array_of_entities']['post']['parameters']).to eql(parameters) end end + + describe 'retrieves the documentation for parameters shared between GET and POST endpoints' do + subject do + get '/swagger_doc/endpoint_with_common_params' + JSON.parse(last_response.body) + end + + describe 'for non-body parameters' do + specify do + expect(subject['paths']['/endpoint_with_common_params']['get']['parameters']).to eql( + [ + { 'in' => 'query', 'name' => "array_of_string#{braces}", 'type' => 'array', 'items' => { 'type' => 'string' }, 'required' => true }, + { 'in' => 'query', 'name' => "array_of_integer#{braces}", 'type' => 'array', 'items' => { 'type' => 'integer', 'format' => 'int32' }, 'required' => true } + ] + ) + end + end + + describe 'for body parameters' do + specify do + expect(subject['paths']['/endpoint_with_common_params']['post']['parameters']).to eql( + [ + { 'in' => 'body', 'name' => 'postEndpointWithCommonParams', 'schema' => { '$ref' => '#/definitions/postEndpointWithCommonParams' }, 'required' => true } + ] + ) + expect(subject['definitions']['postEndpointWithCommonParams']).to eql( + 'type' => 'object', + 'properties' => { + 'array_of_string' => { # no braces, even if array_use_braces is true + 'type' => 'array', + 'items' => { + 'type' => 'string' + } + }, + 'array_of_integer' => { # no braces, even if array_use_braces is true + 'type' => 'array', + 'items' => { + 'type' => 'integer', + 'format' => 'int32' + } + } + }, + 'required' => %w[array_of_string array_of_integer] + ) + end + end + end end end end