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;
"""
Related
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.
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!
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)
}
I have got this Swift code
var request = URLRequest(url: URL(string: "http://www.centill.com/ajax/logreg.php")!)
request.httpMethod = "POST"
let postString = "app_log_pass=\(pass_text_field.text!)"
request.httpBody = postString.data(using: .utf8)
And when my text is
(1&*^&&2
It only prints (1.How can i send string that contains various symbols safely with Swift?
As Sulthan suggested, no predefined CharacterSet can be used for actual servers when you want to include some symbol characters in your POST data.
An example CharacterSet which I often use:
extension CharacterSet {
static let rfc3986Unreserved = CharacterSet(charactersIn:
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~")
}
let postValue = "(1&*^&&2"
let postString = "app_log_pass=\(postValue.addingPercentEncoding(withAllowedCharacters: .rfc3986Unreserved)!)"
print(postString) //->app_log_pass=%281%26%2A%5E%26%262
Another CharacterSet which would work for usual PHP servers:
extension CharacterSet {
static let queryValueAllowed = CharacterSet.urlQueryAllowed.subtracting(CharacterSet(charactersIn: "&+="))
}
let postValue = "(1&*^&&2"
let postString = "app_log_pass=\(postValue.addingPercentEncoding(withAllowedCharacters: .queryValueAllowed)!)"
print(postString) //->app_log_pass=(1%26*%5E%26%262
Anyway, you need to escape the key and the value separately, to prevent escaping the separator =.
ADDITION
An example of escaping multiple key-value pairs:
extension String {
var queryValueEscaped: String {
return self.addingPercentEncoding(withAllowedCharacters: .queryValueAllowed)!
}
}
let params: [String: String] = [
"app_log_usn": "OOPer",//usn_text_field.text!,
"app_log_pass": "(1&*^&&2"//pass_text_field.text!
]
let postString = params.map {"\($0.key)=\($0.value.queryValueEscaped)"}.joined(separator: "&")
print(postString) //->app_log_usn=OOPer&app_log_pass=(1%26*%5E%26%262
Assuming each key is made of safe characters and no need to escape.
Use the addingPercentEncoding method with the urlHostsAllowed parameter:
string.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)
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