Skip to content

Fix issue where array params are sometimes omitted when array_use_braces is true - #957

Merged
numbata merged 7 commits into
ruby-grape:masterfrom
olivier-thatch:fix-array-use-braces
Nov 12, 2026
Merged

numbata merged 7 commits into
ruby-grape:masterfrom
olivier-thatch:fix-array-use-braces

Conversation

@olivier-thatch

@olivier-thatch olivier-thatch commented May 21, 2025 •

Copy link
Copy Markdown
Contributor

Fixes #952.

Summary

Sharing array parameters between GET and POST/PUT/PATCH endpoints no longer drops them from the generated body definition when array_use_braces is on. Nested arrays such as Array[Array[String]] are now documented with every level instead of being flattened to a single array of strings.

Root cause

With array_use_braces: true, RequestParamParsers::Body#parse appends [] to every array param name. It runs before the param's location is known, because that depends on the HTTP method and consumes. Params that become body params (any non-GET without an explicit param_type) kept the braced name, so the body definition got a bogus property or lost the array. The parser also adds the braced copy next to the original, so after renaming, the two collide and the copy was merged over the group's object definition (items.type object became string).

Changes

  • ParseParams strips the [] suffix for array params that end up in the body.
  • params_object drops duplicates by [name, in] before moving params into a body definition. This also removes the duplicate required entries, so the uniq! suggested earlier is no longer needed.
  • Array items are wrapped in one array level per nesting (Array[Array[String]] becomes an array of array of string).

Drawbacks

  • The brace is still added in Body#parse and removed later in ParseParams. This is a patch over a decision made too early; see below.
  • Output changes for anyone who already declared nested arrays: items used to be flattened and now has the inner array. Nested arrays in query/formData params are documented the same way, which is valid in the Swagger 2.0 items schema but unusual for a query string.

Rejected alternatives

  • Not adding the brace in Body#parse: the param's in isn't known there (it depends on method and consumes), so it would need a larger refactor.
  • Set for definition[:required]: changes the interface that other grape-swagger-* gems rely on (Set has no push).
  • Keeping uniq! on required: it only hid the duplicate params.

Not covered

Array[JSON] and JSON params still document type: "json", which is not a Swagger type. That is unrelated to array_use_braces and tracked in #1014.

@dblock

dblock commented May 24, 2025

Copy link
Copy Markdown
Member

CI was fixed in #958, rebase please?

@olivier-thatch
olivier-thatch force-pushed the fix-array-use-braces branch from e4b3778 to eba362d Compare May 28, 2025 16:31
@olivier-thatch olivier-thatch changed the title Fix issue where array params are sometimes omitted when array_use_braces is true Fix issue where array params are sometimes omitted when array_use_braces is true May 29, 2025
@numbata

numbata commented May 31, 2025

Copy link
Copy Markdown
Contributor

Hi @olivier-thatch, a quick fix for this PR could be:

diff --git a/lib/grape-swagger/doc_methods/move_params.rb b/lib/grape-swagger/doc_methods/move_params.rb
index c8417ce..12c6477 100644
--- a/lib/grape-swagger/doc_methods/move_params.rb
+++ b/lib/grape-swagger/doc_methods/move_params.rb
@@ -136,7 +136,7 @@ module GrapeSwagger
           return if value.blank?
 
           definition[:required] ||= []
-          definition[:required].push(*value)
+          definition[:required].push(*value).uniq!
         end
 
         def build_body_parameter(name, options)

I considered using a Set.new for definition[:required] to enforce uniqueness, but that would change the interface (as example, Set doesn’t support .push) and could introduce side effects for other grape-swagger-* gems.

@olivier-thatch
olivier-thatch force-pushed the fix-array-use-braces branch from d19daf7 to 003b77f Compare June 2, 2025 18:29
@numbata

numbata commented Oct 26, 2025

Copy link
Copy Markdown
Contributor

I looked more closely at the PR and noticed we have incorrect behavior for nested arrays. The type Array[Array[String]] collapses into String, so document_array_param only ever sees one dimension. As a result, a declaration like
requires :matrix, type: Array[Array[String]]
produces { type: 'array', items: { type: 'string' } }, which loses the inner array.

We need to either fix this to properly support multi-dimensional arrays or clearly document that they aren’t supported.

@numbata
numbata force-pushed the fix-array-use-braces branch from 06ab743 to e070862 Compare November 3, 2026 12:30
@github-actions

github-actions Bot commented Nov 3, 2026 •

Copy link
Copy Markdown

Danger Report

No issues found.

View run

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

A critical defect leaves deeply nested array schemas with invalid inner item types because array declarations are only unwrapped one level instead of being recursively normalized.

1 open issue
What changed in this PR

This pull request fixes omitted array parameters when array_use_braces is enabled and preserves nested array structure in generated Swagger 2.0 schemas.

Changes:

  • Removes trailing [] from array parameters converted to request-body properties.
  • Deduplicates parameters before body-definition generation.
  • Adds nested-array schema handling and regression coverage.
  • Updates the changelog.

The nested-array implementation still produces invalid leaf item types for declarations such as Array[Array[String]]; recursive type normalization is required before approval.

This pull request requires changes.

File Description
spec/​swagger_v2/​params_array_spec.rb Adds regression coverage for body, query, form, shared, and nested array parameters.
lib/​grape-swagger/​endpoint.rb Deduplicates parameters by name and location before moving body parameters into definitions.
lib/​grape-swagger/​doc_methods/​parse_params.rb Normalizes body array names and attempts to preserve nested array structure; nested leaf types require recursive normalization.
CHANGELOG.md Documents the array-parameter and nested-array fixes.

Review effort: Lite

@numbata
numbata force-pushed the fix-array-use-braces branch from b0a37cb to 537d179 Compare November 12, 2026 22:29
olivier-thatch and others added 7 commits November 13, 2026 00:24
With array_use_braces, the body parser adds a braced copy of every array
param next to the original. Once the brace is stripped for body params the
two collide, and the copy is merged over the group's object definition,
turning items.type from object into string. Dropping the duplicate by name
and location also removes the duplicate required entries, so the uniq!
on required is no longer needed.
Grape passes the declared type as e.g. "[[String]]", but only the
innermost type was documented, so Array[Array[String]] came out as a flat
array of strings. Wrap the items in one array level per leading bracket.
@numbata
numbata force-pushed the fix-array-use-braces branch from 537d179 to 0e02729 Compare November 12, 2026 23:24
@numbata
numbata merged commit de46ec4 into ruby-grape:master Nov 12, 2026
32 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug report: omitted array parameters with array_use_braces: true

4 participants