8000 Round-tripping fails for collapsable object held as `Optional` using `URLEncodedFormEncoder` / `Decoder` · Issue #3329 · vapor/vapor · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Round-tripping fails for collapsable object held as Optional using URLEncodedFormEncoder / Decoder #3329

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
omochi opened this issue May 4, 2025 · 2 comments
Labels
bug Something isn't working

Comments

@omochi
Copy link
omochi commented May 4, 2025

Describe the issue

When holding a potentially empty (“collapsable”) object as an Optional, round-tripping with URLEncodedFormEncoder / Decoder fails.

Vapor version

4.114.1

Operating system and version

macOS 15.3

Swift version

swift-driver version: 1.120.5 Apple Swift version 6.1 (swiftlang-6.1.0.110.21 clang-1700.0.13.3)

Steps to reproduce

When holding a potentially empty (“collapsable”) object as an Optional, round-tripping with URLEncodedFormEncoder / Decoder fails.

By “collapsable”, I mean that the encoded result of the object can become empty.

Here’s an example:

struct Collapsable: Codable, Equatable {
    var optional: Int?
    var array: [Int]
}

This object has two properties. When optional is .none and array is empty, encoding it using URLEncodedFormEncoder results in an empty string.

Now, consider an object holding this as an Optional:

struct ClpOptionalHolder: Codable, Equatable {
    var value: Collapsable?
}

When this object holds a Collapsable instance, encoding and then decoding it using URLEncodedFormEncoder and URLEncodedFormDecoder does not preserve the original value when the Collapsable becomes empty:

func testRoundtripCollapsedHolder() throws {
    let original = ClpOptionalHolder(value: Collapsable(optional: nil, array: []))

    let data = try URLEncodedFormEncoder().encode(original)
    XCTAssertEqual(data, "")

    let decoded = try URLEncodedFormDecoder().decode(ClpOptionalHolder.self, from: data)
    XCTAssertEqual(decoded, original)
}

Is this the intended behavior?

Outcome

No response

Additional notes

I have uploaded a runnable example here for your reference if needed:
https://github.com/omochi/vapor/blob/0c4ddbc7605a33a3e8bb05af1f7e88547a526329/Tests/VaporTests/URLEncodedFormTests.swift#L54-L62

@omochi omochi added the bug Something isn't working label May 4, 2025
@gwynne
Copy link
Member
gwynne commented May 4, 2025

Yes, this is intentional - or more accurately, it is unavoidable. nil values and empty array values can not be unambiguously represented in application/x-www-form-urlencoded encoding. As a result, the Swift type in question by definition can not be round-tripped through that encoding, and it becomes the application's responsibility when using said encoding to ensure that it does not make a semantic distinction between the two different Swift representations. This is analogous to the multiple possible representations of NaN and 0 in a IEEE 754 floating-point value; the floating-point value -0, for example, will fail to roundtrip through most encodings in similar fashion.

It is worth noting that nil and [] both do have unambiguous representations in JSON encoding, if using JSON is possible for your use case.

@gwynne gwynne closed this as not planned Won't fix, can't repro, duplicate, stale May 4, 2025
@omochi
Copy link
Author
omochi commented May 4, 2025

Thank you for the quick response. I understand that this behavior is intentional.
The example with floating-point values was also helpful.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants
0