Skip to content
This repository has been archived by the owner on Nov 16, 2020. It is now read-only.

URLs are encoded being encoded to arrays it seems. #24

Closed
EmperiorEric opened this issue Feb 17, 2020 · 5 comments · Fixed by #25
Closed

URLs are encoded being encoded to arrays it seems. #24

EmperiorEric opened this issue Feb 17, 2020 · 5 comments · Fixed by #25
Labels
bug Something isn't working
Projects

Comments

@EmperiorEric
Copy link
Contributor

I'm sending data to Stripe which requests URLEncodedForm data instead of JSON. And I've run into a strange issue. All my properties of type URL are being sent as arrays. I worked backwards and it appears to be the encoding making a mistake.

struct TestObject: Content {
    let url: URL
    let string: String
    let int: Int
}

let object = TestObject(url: URL(string: "https://onuniverse.com")!, string: "onuniverse.com", int: 99)

let regularEncoder = JSONEncoder()
let regularData = try regularEncoder.encode(object)
print("*** JSONEncoder ***")
print(String(data: regularData, encoding: .utf8)!)

let urlFormEncoder = URLEncodedFormEncoder()
let urlFormEncoderData = try urlFormEncoder.encode(object)
print("*** URLEncodedFormEncoder ***")
print(String(data: urlFormEncoderData, encoding: .utf8)!)

That prints out this:

*** JSONEncoder ***
{"url":"https:\/\/onuniverse.com","string":"onuniverse.com","int":99}
*** URLEncodedFormEncoder ***
string=onuniverse.com&int=99&url[]=https://onuniverse.com

As you can see, the JSON looks correct, single values for url, string, and int. But for the URLEncodedFormEncoder, url appears as an array. And sure enough when sending any URLs to Stripe, I'm getting an error back saying it expected a String but received an Array. I don't know much about URLEncodedForm data to know what the expected behavior actually is or how deep this bug goes.

Work Around
For the time being it appears the only work around is to abandon URL as a type and live with Strings only.

@EmperiorEric
Copy link
Contributor Author

After some additional poking around. Could it be because this library doesn't support encoding/decoding URLs at all?

@tanner0101 tanner0101 added the bug Something isn't working label Feb 17, 2020
@tanner0101
Copy link
Member

@EmperiorEric which version of Vapor are you using?

Foundation.URL's default codable conformance attempts to encode to/from a keyed container: https://github.com/apple/swift-corelibs-foundation/blob/master/Sources/Foundation/URL.swift#L1029-L1055

We should add special support for URL here like JSONEncoder does to serialize it as a simple string.

@EmperiorEric
Copy link
Contributor Author

Vapor 3.3.2
URLEncodedForm 1.0.7

Yea I kept playing and eventually I threw this in and it worked without other changes. I know there is more to the change required to fully support it. So its not so much a bug as it is a missing feature I suppose.

extension URL: URLEncodedFormDataConvertible {
    /// See `URLEncodedFormDataConvertible`.
    func convertToURLEncodedFormData() throws -> URLEncodedFormData {
        return .str(self.absoluteString)
    }

    /// See `URLEncodedFormDataConvertible`.
    static func convertFromURLEncodedFormData(_ data: URLEncodedFormData) throws -> URL {
        guard let url = data.url else {
            throw URLEncodedFormError(identifier: "url", reason: "Could not convert to `URL`: \(data)")
        }

        return url
    }
}

@EmperiorEric
Copy link
Contributor Author

@tanner0101 If I were to work on a PR to fix this, can I aim it at the master branch or do I need to build it for the unreleased v2 branch?

@tanner0101
Copy link
Member

The solution you posted looks good to me. For Vapor 3, target this against master branch. For Vapor 4, this code has been moved into vapor/vapor.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
bug Something isn't working
Projects
No open projects
Vapor 3
  
Done
2 participants