fix!: explode form-urlencoded body array properties by default#195
Closed
t-unit wants to merge 4 commits into
Closed
fix!: explode form-urlencoded body array properties by default#195t-unit wants to merge 4 commits into
t-unit wants to merge 4 commits into
Conversation
Array properties of object schemas in application/x-www-form-urlencoded request bodies were always comma-joined (tags=a,b). Per OAS 3.x the Encoding Object defaults to style: form, explode: true for such properties, which RFC 6570 form expansion serializes as repeated keys (tags=a&tags=b). Element boundaries are now threaded through generated toForm so exploded entries stay lossless even when allowReserved keeps literal commas in element values; an explicit explode: false in the spec preserves the comma-joined form.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #195 +/- ##
==========================================
+ Coverage 92.74% 92.79% +0.05%
==========================================
Files 174 175 +1
Lines 17765 17900 +135
==========================================
+ Hits 16476 16611 +135
Misses 1289 1289
🚀 New features to boost your workflow:
|
Default the per-property explode to true only for form or absent style, per the Encoding Object; spaceDelimited/pipeDelimited arrays keep their previous comma-joined output instead of newly exploding. Duplicate raw names across allOf members now emit exploded elements from the same member whose value wins the parameterProperties merge at runtime, including when later nullable members are null. The exploded-form-array predicate is shared across all three emission sites so alias-wrapped arrays are handled identically everywhere, and the missing-exploded- values exception now names the parameter and points at generator or runtime drift.
Split the form array binding's null test into a member guard and a leaf guard so the exploded-elements channel selects the same winner as the runtime parameterProperties merge: an absent composition member falls through to an earlier duplicate-key candidate, while a present member whose array value is null wins with zero entries, matching the empty string it writes into the merged map. Document the form-body limits (oneOf/anyOf bodies, non-form styles, additionalProperties, null arrays) in the URI encoding guide, drop a dead read-only guard in the allOf binding collector, and omit the empty parameter-name segment from the exploded-values drift exception.
Gate null-aware access and force-unwraps on each link's immediate nullability instead of path-accumulated nullability, so generated guards carry no null-aware operators on non-nullable receivers and no unnecessary non-null assertions. Warn at parse time when a form-body array declares spaceDelimited or pipeDelimited without explode: true, since only the form style is supported and the array is comma-joined. The exploded-values drift exception now names both possible causes instead of ruling out caller input, and the encoder documents the deliberate one-way tolerance for exploded values without descriptors.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
For an
application/x-www-form-urlencodedrequest body whose object schema has an array property, the generated client always sent the comma-joined form:OAS 3.x defines per-property serialization for urlencoded bodies via the Encoding Object, which follows query-parameter defaults:
style: form,explode: true. RFC 6570 form expansion ({?tags*}) serializes that as repeated keys:The comma-joined output is the
explode: falseform, so a conformant server parsed the array as a single element. Additionally, an explicit per-propertyexplodein the spec's Encoding Object was parsed but silently ignored.Fix
toFormnow delivers array elements with boundaries intact (aMap<String, List<String>>alongside the existing property map) instead of pre-flattening them, and the runtime form encoder emits onename=valueentry per element when the property's effective explode is true.explodefrom the Encoding Object is threaded through (FormFieldEncoding); absent an Encoding Object the OAS defaulttrueapplies. An explicitexplode: falsekeeps the comma-joined single entry.allowReserved, where element values may contain literal commas (tags=a,b&tags=cremains two entries).tags=entry. If the runtime is asked to explode a property without element data (an encoder invariant violation), it throws anEncodingExceptionnaming the property instead of silently dropping the field.docs/uri_encoding.mdupdated to describe the new default behavior.Breaking change
The wire format of form-urlencoded bodies with array properties changes from
tags=a,btotags=a&tags=bunless the spec explicitly setsexplode: false. This matches the OAS default; specs relying on the previous behavior should declareexplode: falsein the Encoding Object.Tests
tonik_util: repeated-entry explode, explode=false comma-join, empty list vs[''], element percent-encoding,allowReservedwith comma-containing elements, missing-element-data throw — all with literal expected values.tonik_generate: full-body emission tests for the class path (required, optional null-guarded, nullable-element, immutable-collection) and the allOf path (object member with array property, direct list member, nullable member, duplicate-key last-wins, write-only null-guard).integration_test/form_urlencoded: repeated-key wire assertions, explicitexplode: falsescenario, comma-in-elementallowReservedscenario, round-trip.