Swift URLComponents not converting empty spaces correctly - swift

I have a very simple GET Request in Swift 4 using URLSession for the dataTask and the URLComponents to create the URL/String.
The problem I have is as shown in the code snippet below
var url = URLComponents(string: "http://myServer.com:8086/query")
url?.queryItems = [
URLQueryItem(name: "db", value: "Database"),
URLQueryItem(name: "q", value: ("SELECT valueOne,valueTwo FROM \"TABLE\" WHERE \"valueOne\"='\(currValue)' ORDER BY time DESC LIMIT 1"))
]
NSLog((url?.url?.absoluteString)!)
/*
NSLog: http://myServer.com:8086/query?db=Database&q=SELECT2alueOne,valueTwo
0.000000ROM222TABLE220WHERE222valueOne23D'currValue'
0RDER2Y 0me -8ESC2MIT2
*/
I tried building the URL directly and applying the addingPercentEncoding with urlQueryAllowed on the query part of the string but I still got the same result. The only thing that partially worked was to substitute the empty spaces in the query with "+", but there was still a problem with the escaped inverted comas.
I'm quite new to Swift so my assumption is I'm missing something very obvious. Any and all assistance would be greatly appreciated.

I have created this function to generate URL. You can use this function to create your URL with safe ASCII characters.
func urlGenretor() -> URL{
var components = URLComponents()
components.scheme = "https"
components.host = "myServer.com:8086"
components.path = "/query"
let database = URLQueryItem(name: "db", value: "Database")
let queryItem2 = URLQueryItem(name: "q", value: ("SELECT valueOne,valueTwo FROM \"TABLE\" WHERE \"valueOne\"='\(currValue)' ORDER BY time DESC LIMIT 1"))
components.queryItems = [database,queryItem2]
let url = components.url
print(url!)
return url!

So the answer is that NSLog does not print out percent Escaped strings correctly, print on the other hand does. The best thing would have been just to set a breakpoint on the NSLog line and check the url value if it is correct, which it was.

Related

Swift URL Object returning nil despite po command returning data

I had some trouble creating a URL object, both from a string and using URLComponents.
image of code w/ some debugging messages
var components = URLComponents()
components.scheme = "https"
components.host = "apidojo-yahoo-finance-v1.p.rapidapi.com"
components.path = "/stock/v2/get-statistics"
components.queryItems = [
URLQueryItem(name: "region", value: "US"),
URLQueryItem(name: "symbol", value: "TVIX")
]
let url = components.url
let url = URL(string: "https://apidojo-yahoo-finance-v1.p.rapidapi.com/stock/v2/get-statistics?region=US&symbol=\(stockSymbol)")
link to API documentation page
However, when testing the code, the url Object returns nil, despite using the po command in the 11db xcode console and seeing it return data (though using the "p" and "v" commands gave nil).
Anyone know how to construct the URL to properly contain data?
Any help is appreciated!

Swift Quotation Mark in URL

I'm trying to do a request with Alamofire to this url:
https://overpass-api.de/api/interpreter?data=[out:json];(way[highway~"^(motorway)$"][!maxspeed](around:5,45.792790,3.062686););out%20tags;
but it contains a double quotation mark and the cast into URL fails.
I've escaped the " with the backslash
let urlString = "https://overpass-api.de/api/interpreter?data=[out:json];(way[highway~\"^(motorway)$\"][!maxspeed](around:5,45.792790,3.062686););out%20tags;"
but when I convert the string in a URL, it returns nil
let url = URL(string: urlString)
I've tried replacing the " symbols with %22, but it is still not working. I tried using the addingPercent but it results in a wrong url and returns error 400 or 404
let urlWithEconding = urlString.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)
I also tried to use AlamoFire method for url casting and encoding, but I cannot make it work...
Here is how you can use URLComponents
let queryValue = "[out:json];(way[highway~\"^(motorway)$\"][!maxspeed](around:5,45.792790,3.062686););out tags;"
var components = URLComponents()
components.scheme = "https"
components.host = "overpass-api.de"
components.path = "/api/interpreter"
components.queryItems = [URLQueryItem(name: "data", value: queryValue)]
If you don't want to escape the quotes you can define the variable like this
let queryValue = """
[out:json];(way[highway~"^(motorway)$"][!maxspeed](around:5,45.792790,3.062686););out tags;
"""

How can I convert the string to URL which include a ? in the string by Swift 4.2

As the title, I am using Google Places API, the URL has a question mark, when I send a request, it will become %3F, how can I modify my code by Swift 4.2??
I found a lot of information but they were using Swift 2 or 3, so it is unavailable for me!
UPDATE my code
let urlString = "\(GOOGLE_MAP_API_BASEURL)key=\(GMS_HTTP_KEY)&input=\(keyword)&sessiontoken=\(ver4uuid!)"
print(urlString)
if let encodedString = urlString.addingPercentEncoding(withAllowedCharacters: CharacterSet.alphanumerics
.union(CharacterSet.urlPathAllowed)
.union(CharacterSet.urlHostAllowed)) {
print("encodedString: \(encodedString)")
You are supposed to encode only the query parameters (although probably only keyword actually needs encoding), not the whole URL.
func urlEncode(_ string: String) -> String {
var allowed = CharacterSet.urlQueryAllowed
allowed.remove(charactersIn: "!*'();:#&=+$,/?%#[]")
return string.addingPercentEncoding(withAllowedCharacters: allowed) ?? ""
)
let urlString = "\(GOOGLE_MAP_API_BASEURL)key=\(urlEncode(GMS_HTTP_KEY))&input=\(urlEncode(keyword))&sessiontoken=\(urlEncode(ver4uuid!))"
print(urlString)
Also see Swift - encode URL about the correct way to encode URL parameters.
In this case I highly recommend to use URLComponents and URLQueryItem which handles the percent escaping very smoothly.
var urlComponents = URLComponents(string: GOOGLE_MAP_API_BASEURL)!
let queryItems = [URLQueryItem(name: "key", value: GMS_HTTP_KEY),
URLQueryItem(name: "input", value: keyword),
URLQueryItem(name: "sessiontoken", value: ver4uuid!)]
urlComponents.queryItems = queryItems
let url = urlComponents.url!

Safely sending base64 encoded string as query parameter

In my app, I need to send to a server a base64-encoded string as a query parameter, eg.
&data=AwGZnyx+JUi0PFJoyYSEDpgtlrxP(cut...)==
Problem is, anything works just fine when there isn't a plus sign in my string: on the other hand, everytime there's one, the server code doesn't behave correctly.
I noticed there are escaping functions (eg. addingPercentEncoding) but they don't work with the plus sign.
Aside from removing all the pluses "manually" (eg. with a regex), is there anything else I can do?
At the moment anything works fine if I use:
string.replacingOccurrences(of: "+", with: "%2B")
The server is probably interpreting the + sign as a space because it is often used in query parameters as a substitute for a space. addPercentEncoding isn't going to help you because it only translates non ASCII characters.
You'll need to manually replace + with %2B as you are doing.
.... although
NSString has a version of addPercentEncoding that also takes a CharacterSet as a parameter. So you could create a Characterset with all the base64 characters in it except + using init(charactersIn:) i.e.
let safeChars = Characterset(charactersIn: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrtuvwxyz0123456789/=")
One good way to construct a URL is to use URLComponents. This should work in almost all cases, and an example is shown below:
let base64 = "AwGZnyx+JUi0PFJoyYSEDpgtlrxP(cut...)=="
var components = URLComponents(string: "https://example.com")
components?.queryItems = [ URLQueryItem(name: "data", value: "AwGZnyx+JUi0PFJoyYSEDpgtlrxP(cut...)==") ]
let url = components?.url
Result:
https://example.com?data=AwGZnyx+JUi0PFJoyYSEDpgtlrxP(cut...)%3D%3D
However, in your particular case, it seems the the server is not correctly handling the + and you need to work around that issue similar to what you have above. The better fix would be for the server to be changed to correctly process the URL.
let base64 = "AwGZnyx+JUi0PFJoyYSEDpgtlrxP(cut...)=="
var components = URLComponents(string: "https://example.com")
components?.queryItems = [ URLQueryItem(name: "data", value: base64) ]
let urlString = components?.string.replacingOccurrences(of: "+", with: "%2B")
Result:
https://example.com?data=AwGZnyx%252BJUi0PFJoyYSEDpgtlrxP(cut...)%3D%3D

Swift URL appendPathComponent replaces ? with %3F

I have a router which contains the lines
var url = URL(string: MyRouter.baseURLString)!
url.appendPathComponent(relativePath)
This replaces "?" with "%3F" which is rejected by the API server. How can I fix this? It's wrong to encode that character.
Because the ? isn't part of a path. It's a separator to signal the beginning of the query string. You can read about the different components of a URL in this article. Each component has its set of valid characters, anything not in that set needs to be percent-escaped. The best option is to use URLComponents which handles the escaping automatically for you:
var urlComponents = URLComponents(string: MyRouter.baseURLString)!
urlComponents.queryItems = [
URLQueryItem(name: "username", value: "jsmith"),
URLQueryItem(name: "password", value: "password")
]
let url = urlComponents.url!