URLQueryItem value is optional - ios

Hello I am trying to add queryItems to my URLComponents but because URLQueryItem returns its value as an optional the url keeps having a question mark in it.
var params = ["id":"5"]
let queryParams = toStringDictionary(dictionary: params).map { pair in
return URLQueryItem(name: pair.key, value: pair.value)
}
var components = URLComponents(string: fullURL)
components.queryItems = queryParams
print(components.url)//This is the full url https://demo.com/users/?5
//This https://demo.com/users/?5 should be this https://demo.com/users/5
The question mark is of course resulting in a wrong url. I can't get rid of it.

Query parameters are separated from the rest of the url by a question mark, for example:
https://example.com/path?param_name=param_value
The question mark is not due to an optional, but is the way that query params are supplied.
The example in your comment looks like it has lost the name of the param, I would expect it to read
https://demo.com/users/?id=5
If it definitely doesn't include the id= bit, please could you share the implementation of toStringDictionary so that we can see what's going on there? The dictionary you pass in is already a string dictionary, so seems odd to have such a function.
EDIT: following your clarifications (which have now disappeared, but made it clear that you were looking to add to the path rather than the query string)
It looks like your code is adding query parameters correctly; look closer at the URL it produces, it will be https://demo.com/users/?id=5. Query parameters are not part of the path, they come at the end and are separated from the rest of the URL by a ?
From your edits, it looks as though what you actually want to do is to add to the path of the URL, so that you get https://demo.com/users/5. That URL does not have any query parameters, so URLQueryItem is the wrong tool for the job.
To add to the path, you can do something like the following:
let userID = "5"
let url = URL(string: "https://example.com/users")!
let newUrl = url.appendingPathComponent(userID)
print(newUrl.absoluteString) //https://example.com/users/5
NB - url is only force unwrapped for brevity in the example, since the string passed to URL() is known to be valid. In real use, you should treat the optional more carefully.

There's something wrong with your toStringDictionary
Assuming
let fullURL = "https://demo.com/users/"
all you need to do is…
let queryParams = params.map{ URLQueryItem(name: $0, value: $1) }
var components = URLComponents(string: fullURL)!
components.queryItems = queryParams
print(components.url!)
// https://demo.com/users/?id=5
Note that you should avoid the force unwrapping in practice

Related

What is the purpose of calling text.flatMap(URL.init)?

What is the purpose of calling text.flatMap(URL.init) in the following:
guard let url = someUITextField.text.flatMap(URL.init) else {
return true
}
someUITextField.text is assumed to have a URL string that a user entered.
text is an optional and URL(init) returns also an optional. The result is a double optional URL??
flatMap first transforms the String? to URL?? then it removes one ? to be able to if let the expression.
Please read What’s the difference between map(), flatMap() and compactMap()? on hackingwithswift for details.

Swift Encode Custom String to populate URL [duplicate]

This question already has answers here:
Swift - encode URL
(19 answers)
Closed 2 years ago.
I have a URL that takes any String like this:
https://test#api.search?query=\(productSearchString)&limit=1
Now my problem is that this works with for example "iphone" but it crashes with "iphone 12".
I tried encoding it like this:
guard let escapedResourceString = resourceString.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed) else { return }
but this doesn't seem to work in my case because it is returning an incorrect URL that I can not use with my API.
How can I fix this, so the user can type in anything he want but the URL should be created and my API should be able to work with it.
If you need anything more just let me know.
Your parameters needs to be url encoded.
You can use URLComponents to create your URL and pass your parameters as URLQueryItem instances, like that:
let productSearchString = "iphone 12"
var urlComponents = URLComponents(string: "https://test#api.search")
urlComponents?.queryItems = [
URLQueryItem(name: "query", value: productSearchString),
URLQueryItem(name: "limit", value: "1")
]
let url = urlComponents?.url
print(url?.absoluteString ?? "nil") // https://test#api.search?query=iphone%2012&limit=1

Converting string (Contains json string) to NSURL in swift

I have PAI its Implemented in .NET.
one of the web service url is like this
http://123.321.33/UploadCitizenImage?jsonString={\"Mobile\":\"12345678\", \"fileName\":\"7661832460_05072018.png\"}
while converting above string to URL in swift, app going crash.
for more info check this
The URL(string:) initializer returns an optional since the parsing of the string may fail. In that case, nil is returned. That's exactly what's happening here since the string you are providing is not a valid URL: there are several characters in the query that are not allowed there and need to be replaced: { as %7B, " as %22, space as %20 and } as %7D.
So the initializer returns nil. Next thing you do is force unwrap via the ! operator. But force-unwrapping a nil is illegal and is why you get the crash.
If you want to create an URL, please look into the URLComponents class which does all the necessary escaping for you so you don't need to care about it. The queryItems property is of particular interest for you, it's an array of URLQueryItem.
Please do something like that,
let jsonString = "jsonString={\"Mobile\":\"12345678\", \"fileName\":\"7661832460_05072018.png\"}" as String
let urlEncoadedJson = jsonString.addingPercentEncoding(withAllowedCharacters:.urlHostAllowed)
let urls = NSURL(string:"http://123.321.33/UploadCitizenImage?\(urlEncoadedJson ?? "")")
First convert your json into encodedJson then add into your url.
Do let me know if there is some issue.
You can try this,
let string = "http://123.321.33/UploadCitizenImage?jsonString={\"Mobile\":\"12345678\", \"fileName\":\"7661832460_05072018.png\"}"
let escapedString = string.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)
let url = URL(string: escapedString!)!
print(url)
Output will be like this,
http://123.321.33/UploadCitizenImage?jsonString=%7B%22Mobile%22:%2212345678%22,%20%22fileName%22:%227661832460_05072018.png%22%7D

iOS: Prevent URL from being percent escaped automatically?

I'm fetching some JSON data using URLSession.dataTask. To filter the data, I'm using a parameter that limits by date. The API uses square brackets for this, e.g.
https://foo.com/api/items.json?find[date]=....
However, upon creating a URL with the string and requesting data from it, the square brackets are automatically escaped:
https://foo.com/api/items.json?find%5Bdate%5D=...
With the brackets escaped, the API fails to recognize the request.
I've tried explicitly removing the percent encoding to create a new URL, i.e.
let unsanitized = URL(string: url.absoluteString.removingPercentEncoding)
but the percent sanitization persists.
I've spent a lot of time searching for a solution but haven't had any success—any suggestions?
Per the spec for URI: "A host identified by an Internet Protocol literal address, version 6 [RFC3513] or later, is distinguished by enclosing the IP literal within square brackets ("[" and "]")." rfc3986.
Thus you can't use square brackets for your purpose without escaping them. Your server's REST service is at fault for not handling the escaped characters in the query params. (And I've had situations in recent past where I've had to ask my REST team to fix this sort of problem where they forgot to support escaped query parameter values).
Try use percentEncodedQueryItems of URLComponents instead queryItems.
This is my codes in my app.
let fullUrl = baseURL.appendingPathComponent(path)
guard var components = URLComponents(url: fullUrl, resolvingAgainstBaseURL: false) else {
fatalError("Unable to create URL components")
}
var params = self.parameters // <-- parameters = [String:String]
params["serviceKey"] = Const.OPEN_API_KEY // <-- percent encoded key
components.percentEncodedQueryItems = params.map { // <-- already percent encoded Query Items
URLQueryItem(name: String($0), value: String($1))
}
guard let url = components.url else {
fatalError("Could not get url")
}

What is the function of URLQueryItem in swift?

I am a beginner in iOS development, recently I am learning about networking with rest API in iOS development. When constructing URL to make request, I found code like this:
var queryComponents: [URLQueryItem] {
var components = [URLQueryItem]()
for (key, value) in parameters {
let queryItem = URLQueryItem(name: key, value: "\(value)")
components.append(queryItem)
}
return components
}
I don't understand why the array component shall be in URLQueryItem data type.
Thanks in advance :)
Actually in URLComponents has a property called queryItems which requires array of URLQueryItem, Its purpose is to add number of parameters in the API request
In your case why they would have implemented queryComponents as an array is that they would have been assigning multiple URLQueryItems for a request in queryComponents.
Eg:
queryComponents.append(NEW_URLQueryItem1)
queryComponents.append(NEW_URLQueryItem2)
And finally when we access queryComponents we will get array value which we can directly assign to URLComponents as follows,
var urlComponents = URLComponents(string: "API_URL")
urlComponents.queryItems = queryComponents

Resources