From 4ee22a7b60e24779fd168b2feefaa8e959631f4c Mon Sep 17 00:00:00 2001 From: khiav reoy Date: Thu, 21 Aug 2025 23:43:58 +0800 Subject: [PATCH 1/4] refactor: extract schema building method from build_response_for_type_parameter --- lib/grape-swagger/endpoint.rb | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/lib/grape-swagger/endpoint.rb b/lib/grape-swagger/endpoint.rb index 54dd8191..a3d377c7 100644 --- a/lib/grape-swagger/endpoint.rb +++ b/lib/grape-swagger/endpoint.rb @@ -311,15 +311,24 @@ def build_memo_schema(memo, route, value, response_model, options) end def build_response_for_type_parameter(memo, _route, value, _options) - type, format = prepare_type_and_format(value) + schema = build_response_schema(value) if memo[value[:code]].include?(:schema) && value.include?(:as) - memo[value[:code]][:schema][:properties].merge!(value[:as] => { type: type, format: format }.compact) + memo[value[:code]][:schema][:properties].merge!(schema) elsif value.include?(:as) - memo[value[:code]][:schema] = - { type: :object, properties: { value[:as] => { type: type, format: format }.compact } } + memo[value[:code]][:schema] = { type: :object, properties: schema } + else + memo[value[:code]][:schema] = schema + end + end + + def build_response_schema(value) + type, format = prepare_type_and_format(value) + + if value.include?(:as) + return { value[:as] => { type: type, format: format }.compact } else - memo[value[:code]][:schema] = { type: type } + return { type: type } end end From 6e9767408a71d6526bdb6d8fc6758b5f960c3884 Mon Sep 17 00:00:00 2001 From: khiav reoy Date: Fri, 22 Aug 2025 00:04:57 +0800 Subject: [PATCH 2/4] handle arrays of primitive data types in response --- lib/grape-swagger/endpoint.rb | 12 ++--- ...se_with_models_and_primitive_types_spec.rb | 45 ++++++++++++++++++- 2 files changed, 50 insertions(+), 7 deletions(-) diff --git a/lib/grape-swagger/endpoint.rb b/lib/grape-swagger/endpoint.rb index a3d377c7..6d9f65e4 100644 --- a/lib/grape-swagger/endpoint.rb +++ b/lib/grape-swagger/endpoint.rb @@ -323,13 +323,15 @@ def build_response_for_type_parameter(memo, _route, value, _options) end def build_response_schema(value) - type, format = prepare_type_and_format(value) + return { value[:as] => build_response_schema(value.except(:as)) } if value.include?(:as) - if value.include?(:as) - return { value[:as] => { type: type, format: format }.compact } - else - return { type: type } + if value[:type].is_a?(Array) + items = build_response_schema({ **value, type: value[:type].first }) + return { type: 'array', items: items } end + + type, format = prepare_type_and_format(value) + { type: type, format: format }.compact end def prepare_type_and_format(value) diff --git a/spec/swagger_v2/api_swagger_v2_response_with_models_and_primitive_types_spec.rb b/spec/swagger_v2/api_swagger_v2_response_with_models_and_primitive_types_spec.rb index 8050f1b6..161ac025 100644 --- a/spec/swagger_v2/api_swagger_v2_response_with_models_and_primitive_types_spec.rb +++ b/spec/swagger_v2/api_swagger_v2_response_with_models_and_primitive_types_spec.rb @@ -16,7 +16,12 @@ class ResponseApiModelsAndPrimitiveTypes < Grape::API { model: Entities::UseResponse, as: :user_response }, { type: 'String', as: :string_response }, { type: 'Float', as: :float_response }, - { type: 'Hash', as: :hash_response } + { type: 'Hash', as: :hash_response }, + { type: Array[Integer], as: :array_of_integer_response }, + { type: Array[String], as: :array_of_string_response }, + { type: Array[Float], as: :array_of_float_response }, + { type: Array[Hash], as: :array_of_hash_response }, + { type: Array[Array[Float]], as: :array_of_array_of_float_response } ], failure: [ { code: 400, message: 'NotFound', model: '' }, @@ -56,7 +61,43 @@ def app 'integer_response' => { 'type' => 'integer', 'format' => 'int32' }, 'string_response' => { 'type' => 'string' }, 'float_response' => { 'type' => 'number', 'format' => 'float' }, - 'hash_response' => { 'type' => 'object' } + 'hash_response' => { 'type' => 'object' }, + 'array_of_integer_response' => { + 'type' => 'array', + 'items' => { + 'type' => 'integer', + 'format' => 'int32' + } + }, + 'array_of_string_response' => { + 'type' => 'array', + 'items' => { + 'type' => 'string' + } + }, + 'array_of_float_response' => { + 'type' => 'array', + 'items' => { + 'type' => 'number', + 'format' => 'float' + } + }, + 'array_of_hash_response' => { + 'type' => 'array', + 'items' => { + 'type' => 'object' + } + }, + 'array_of_array_of_float_response' => { + 'type' => 'array', + 'items' => { + 'type' => 'array', + 'items' => { + 'type' => 'number', + 'format' => 'float' + } + } + } } } }, From 2161e51a22ff16b9f670a512502f1355a9ba53f5 Mon Sep 17 00:00:00 2001 From: khiav reoy Date: Fri, 22 Aug 2025 00:29:02 +0800 Subject: [PATCH 3/4] add support for oneOf primitive types inside response arrays --- lib/grape-swagger/endpoint.rb | 7 ++++++- ..._response_with_models_and_primitive_types_spec.rb | 12 +++++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/lib/grape-swagger/endpoint.rb b/lib/grape-swagger/endpoint.rb index 6d9f65e4..990d4fa1 100644 --- a/lib/grape-swagger/endpoint.rb +++ b/lib/grape-swagger/endpoint.rb @@ -326,7 +326,12 @@ def build_response_schema(value) return { value[:as] => build_response_schema(value.except(:as)) } if value.include?(:as) if value[:type].is_a?(Array) - items = build_response_schema({ **value, type: value[:type].first }) + items = if value[:type].size == 1 + build_response_schema({ **value, type: value[:type].first }) + else + { oneOf: value[:type].map { |type| build_response_schema({ **value, type: type }) } } + end + return { type: 'array', items: items } end diff --git a/spec/swagger_v2/api_swagger_v2_response_with_models_and_primitive_types_spec.rb b/spec/swagger_v2/api_swagger_v2_response_with_models_and_primitive_types_spec.rb index 161ac025..76979f90 100644 --- a/spec/swagger_v2/api_swagger_v2_response_with_models_and_primitive_types_spec.rb +++ b/spec/swagger_v2/api_swagger_v2_response_with_models_and_primitive_types_spec.rb @@ -21,7 +21,8 @@ class ResponseApiModelsAndPrimitiveTypes < Grape::API { type: Array[String], as: :array_of_string_response }, { type: Array[Float], as: :array_of_float_response }, { type: Array[Hash], as: :array_of_hash_response }, - { type: Array[Array[Float]], as: :array_of_array_of_float_response } + { type: Array[Array[Float]], as: :array_of_array_of_float_response }, + { type: Array[Integer, String], as: :array_of_integer_or_string_response } ], failure: [ { code: 400, message: 'NotFound', model: '' }, @@ -97,6 +98,15 @@ def app 'format' => 'float' } } + }, + 'array_of_integer_or_string_response' => { + 'type' => 'array', + 'items' => { + 'oneOf' => [ + { 'type' => 'integer', 'format' => 'int32' }, + { 'type' => 'string' } + ] + } } } } From f59d9cfa25d330a74e2235ea02d8fe035a475358 Mon Sep 17 00:00:00 2001 From: khiav reoy Date: Fri, 5 Sep 2025 11:44:09 +0800 Subject: [PATCH 4/4] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index aa559f7e..08c30053 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ * [#953](https://github.com/ruby-grape/grape-swagger/pull/953): Added `super_diff` - [@numbata](https://github.com/numbata). * [#951](https://github.com/ruby-grape/grape-swagger/pull/951): Use `x-example` for non-body parameters - [@olivier-thatch](https://github.com/olivier-thatch). * [#963](https://github.com/ruby-grape/grape-swagger/pull/963): Allow empty model definitions for swagger 2.0 - [@numbata](https://github.com/numbata). +* [#964](https://github.com/ruby-grape/grape-swagger/pull/964): Add support for array of primitive data types in responses - [@khiav223577](https://github.com/khiav223577). * Your contribution here. #### Fixes