kean / Get

Web API client built using async/await
MIT License
943 stars 75 forks source link

Encode '+' in query string #35

Closed alsaybar closed 2 years ago

alsaybar commented 2 years ago

Hello @kean. Thank you for this library, I really admire the elegant API you achieved with this.

I've been using Get in a side project and stumbled into an issue where an explicitly written + character was not encoded when used in a query string (e.g. domain.tld?query=value1+value2). This resulted in an unexpected response from the API i was using.

According to a note in this Apple Doc which also refers to RFC 3986 and W3C, the + sign is a valid character for representing a space in a query string. Due to this fact it seems, the character is not automatically encoded when reading the url from a URLComponents instance. The same note suggests to preemptively encode the + character as well if needed.

I think it would be reasonable to add this behavior to Get, what are your thoughts?

I made a sample implementation in a fork here. Heavily inspired by Alamofire.

kean commented 2 years ago

Hi,

Depending on the implementation receiving this URL, you may need to preemptively percent-encode the plus sign character. As an alternative, consider encoding complex and/or potentially problematic data in a more robust data-interchange format, such as JSON or XML.

The recommendation seems to be to preemptively encode it if needed, which can be done from the client code. I would prefer to avoid adding workarounds that are only needed for specific servers and/or requests. Get is consistent with the native behavior and this note applies to it as well.

alsaybar commented 2 years ago

I attempted to perform the encoding in my own code without luck. Am I missing something here?

Example:

// encoded version of "value1+value2".
let queryValue = "value1%2Bvalue2"

let queryItem = URLQueryItem(name: "query", value: queryValue)
var urlComponents = URLComponents()
urlComponents.queryItems = [queryItem]

// This is the query value of the final request being sent
urlComponents.percentEncodedQuery
// "query=value1%252Bvalue2"

As you can see, the percentEncodedQuery ends up being double encoded if you will. %2B becomes %252B and thus not decoded into a + when reaching the server.

kean commented 2 years ago

Yeah, you are absolutely right – it double-encodes it. I didn't think it through.

URLComponents allows you to set percentEncodedQuery in case you want to encode the query yourself, but Get, of course, doesn't allow you to do it currently.

Are there any scenarios in which you don't want percent-encoding + by default? I think yes, in case someone uses + as a "space" shorthand – the way it's specified.

What do you think about adding a new delegate method to allow users to customize how URL and/or URLRequest are created?

alsaybar commented 2 years ago

Adding a delegate would be a fine way to do it and in line with other customization points!

My initial suggestion is absolutely too rigid/hardcoded and I respect that Get should stay as lean and close to the native behavior.

kean commented 2 years ago

I added the new delegate method in Get 1.0 (RC1)