sean7512 / RestEssentials

Lightweight REST and JSON library for Swift.
MIT License
37 stars 12 forks source link

query string "?" passed in via "at:" parameter is encoded to "%3F" #22

Closed ohgasauraus closed 4 years ago

ohgasauraus commented 5 years ago

Hi, I been experiencing issue when trying to use the get function in the RestController to retrieve a list. The "at:" parameter when passed in with query string, will auto encode the "?" to "%3F" and cause my spring framework server to read the entire query string as part of the URL path literal instead.

Below is my code snippet of my calls: rest.get(withDeserializer: JSONDeserializer(), at: "/list?page=0&size=10&sort=name,asc", options: header, callback: {result, response in print("\(result)\n\n\(response)"})

the url that was called (copied from response print) as: http://localhost:8095/itam/api/asset/list%3Fpage=0&size=10&sort=name,asc

I have tested the server call to be working using the "?" instead of "%3F" via postman chrome extension.

Is it possible not to encode the "?" or provide a query string parameter so that the query string doesn't get encoded?

sean7512 commented 5 years ago

To use query parameters, you will need to use Apple's URL/URLComponents API instead of using a raw string.

A quick sample may look something like this (excuse all the force unwrapping...just a very quick, sloppy example).

let baseURL = URL(string: "http://httpbin.org/get")!
var components = URLComponents(url: baseURL, resolvingAgainstBaseURL: false)
components!.queryItems = []
components!.queryItems?.append(URLQueryItem(name: "name", value: "Bob"))
let rest = RestController.make(url: components!.url!)
ohgasauraus commented 5 years ago

However by doing the suggested method, I can no longer use 1 RestController for all my calls. Every time when query string is required, I need to create a new RestController which go against the suggested usage of using only 1 RestController for every the calls as mention in your notes:

All of the operations can also take a relative path to be used. If your RestController object is for http://foo.com you can pass in some/relative/path, then the request will go to http://foo.com/some/relative/path. This enables you to use a single RestController object for all REST calls to the same host. This IS the preferred behavior instead of creating a new RestController for every call.

sean7512 commented 5 years ago

The main concern (minor concern anyways) is continually creating a new URL object form a String. If you define the base URL object in your project then make a new RestController using the new URL, it'll be fine.

As of now, that is the only way to do GET parameters. Feel free to create a pull request that adds an optional [URLQueryItem] object to the GET calls, that way you could use a single RestController and pass in different query items. I do not know when I'll get around to doing it, but it is on my list to do in a future update.

sean7512 commented 5 years ago

Also, given all RestControllers use the shared NSURLSession, creating multiple of them is not a huge concern. At one point, I toyed with the idea of allowing you to specify a new URLSession; however I never allowed that because it made the API too messy. If I did that, then you definitely would want to stay away from creating too many.