SWIFT URL String build - swift

How do I build the URL as below:
/sap/opu/odata/SAP/ZTM_FOR_MOBILITY_SRV/BusinessPartnerSet('BP-CR-EM01')/?$format=json
I want specifically the part - BusinessPartnerSet('BP-CR-EM01').
BP-CR-EM01 value is dynamic value.
let newUrl = url + "'\(businessPartners[myIndex].partnerId)'"
url has the fixed URL and the + operator followed by dynamic value. Please help me with your suggestions.

I recommend to use URLComponents
var components = URLComponents(string: "http://mycompany.com")!
components.path = "/sap/opu/odata/SAP/ZTM_FOR_MOBILITY_SRV/BusinessPartnerSet('\(businessPartners[myIndex].partnerId)')/"
components.queryItems = [URLQueryItem(name: "$format", value:"json")]
if let url = components.url {
print(url)
// or if you need the string
print(url.absoluteString)
}

Related

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;
"""

URL Object is nil after creating it with let constant string url

Why does the first example give me a nil and the second example give me a valid URL object. I am trying to use this jsonUrlString constant and it's not working.
1)
let jsonUrlString = """
https://myURI.domain.com/
"""
let temp = URL(string: jsonUrlString)
2)
let temp = URL(string: "https://myURI.domain.com/")
The first example has lots of extra spaces in the URL so it's not valid.
It's the same as:
let temp = URL(string: " https://myURI.domain.com/")
It would work if you had:
let jsonUrlString = """
https://myURI.domain.com/
"""
This defines the string without the extra spaces.

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!

Reading URLS in JSON api with swift

For work we have a third party company which supply a JSON api for some functionality. The JSON contains urls which I try to map in my code with URL(string: ...) but this fails on some urls which have spaces.
For example:
var str = "https://google.com/article/test test.html"
let url = URL(string: str) //nil
Should I ask the third party to encode their URLs ?
Is this normal or should I try to add encoding myself?
Encoding myself is hard I think because the path should be encoded different from the query and the host shouldn't be encoded etc.
Or am I overthinking this?
If the URL contains spaces in its path, escape the characters with addingPercentEncoding(withAllowedCharacters passing the urlPathAllowed character set:
let str = "https://google.com/article/test test.html"
if let escapedString = str.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlPathAllowed),
let url = URL(string:escapedString) {
print(url)
} else {
print("url \(str) could not be encoded")
}
What I would do if I were you, is to split the string up on the space, try converting each of the elements to a url, and when that works save it in your variable.
var str = "https://google.com/article/test test.html"
var url: URL? = nil
for urlString in str.components(separatedBy: .whitespacesAndNewlines) {
let url = URL(string: urlString)
if url != nil {
break
}
}
// url might be nil here, so test for value before using it
If each URL that you get from the API is in the format in your example, you can instead just grab the first element after spitting the string.
var str = "https://google.com/article/test test.html"
if let urlString = str.components(separatedBy: .whitespacesAndNewlines).first {
let url = URL(string: urlString)
}
// url might be nil here, so test for value before using it

Swift: define a variable then conditionally set it?

This is probably a very simple question...
Here I have some Swift code:
var url: NSURL
if (someValue > 1) {
var fullUrl = self.baseUrl + "?id=" + (someValue as! String);
var url = NSURL(string: fullUrl);
}
else {
var url = NSURL(string: self.baseUrl);
}
let req = NSURLRequest(URL: url);
webView.loadRequest(req);
As you can see, I need to conditionally initialize the url variable. However, the method I've used in just about every other strong-type language - initialize the variable then assign to it in the if statement - doesn't seem to be the Swiftly way of doing it.
The above code will refuse to compile with the error "variable 'url' used for being initialized" error. (Of course, from this program flow, you can see that url would always be initialized, but Swift apparently takes nothing for granted.)
Not defining the variable outside the if block results in an unknown identifier error - it seems variables defined inside an if block are scoped only within that block.
Short of just defining an empty NSURL object, is there a better way to do this?
Preferably I'd actually like to use let on this because the NSURL object will never change once it's been created - and Swift tends to recommend using let wherever possible. However, how would you use let in this scenario? (I tried it - the same types of errors occur. Swift is unhappy that I don't actually declare the object itself on the same line as the let statement, but using let inside the if block results in a scope issue.)
The problem is you're redefining url as var url = NSURL(string: self.baseUrl); within the context of the if-else so the url outside is never actually set.
This will fix the error and allow you to use let for url.
let url: NSURL
if (someValue > 1) {
var fullUrl = self.baseUrl + "?id=" + (someValue as! String);
url = NSURL(string: fullUrl);
} else {
url = NSURL(string: self.baseUrl);
}
let req = NSURLRequest(URL: url);
webView.loadRequest(req);
You are redeclaring your property each time you try to set it. Try:
url = /*stuff here*/;
inside your if statements instead of:
var url = /*stuff here*/;
You have to define outside of the {}, that sets it's scope. In your code you're redefining url in the if and the else, you need to remove the re-declaration of "var" so that you can assign your url to the url out of the scope of the if / else statement.
You can use another if statement to check for nil and unwrap it if it's not nil, like
if url != nil {
let req = NSURLRequest(URL: url!)
}
You variable url need to be conditional do something like this.
var url: NSURL?
if (someValue > 1) {
var fullUrl = self.baseUrl + "?id=" + (someValue as! String);
url = NSURL(string: fullUrl);
}
else {
url = NSURL(string: self.baseUrl);
}
let req = NSURLRequest(URL: url);
webView.loadRequest(req);