Unable to convert string to URL in Swift iOS - ios

In order to make HTTP request call using URLSession,I need to convert string to URL first so I have tried everything but just can’t convert this piece of string to URL(string: ).
This is the string:
“http://api-aws-eu-qa-1.abc-cde.com/v1/car-types/manufacturer?page=0&pageSize=10&wa_key=abc-cde-efg-44ccd99”
I can’t share the exact Url but format is all same.
The actual url with same format works fine in browser but no way in Swift, also that works fine in POSTMAN
I have also tried URLComponents which hepls me create the URL from components to URL but that fails with 400 status code response error.
I really appreciate the help, I am completely bogged down with this isuue and can’t proceed with my assignment.
Update: Tested with fiddler and request was not going through with this URL - "“http://api-aws-eu-qa-1.abc-cde.com%E2%80%8B/v1/car-types/manufacturer?page=0&pageSize=10&wa_key=abc-cde-efg-44ccd99”"
But when removed this %E2%80%8B in fiddler and resend it worked.
Any thoughts ..?

String to URL
let url = URL(string: "the url string goes here")
URL to String
let url = URL(string: "the url string goes here")
let urlString = url.absoluteString
Creating URL from URLComponents
var url: URL? {
var components = URLComponents()
components.scheme = "https"
components.host = "domain goes here" //example: twitter.com
components.path = "/path/goes/here"
components.queryItems = [
URLQueryItem(name: "item1", value: string1),
URLQueryItem(name: "item2", value: string2)
]
return components.url
}

try to add HEADER to you request:
let url = URL(string : urlString)
var request = URLRequest(url : url)
request.setValue("Application/json", forHTTPHeaderField : "Content-Type")

Your URL is:
http://api-aws-eu-qa-1.abc-cde.com%E2%80%8B/v1/car-types/manufacturer?page=0&pageSize=10&wa_key=abc-cde-efg-44ccd99`
The "host" portion is:
api-aws-eu-qa-1.abc-cde.com%E2%80%8B
%E2%80%8B encodes a ZERO WIDTH SPACE. This is a perfectly valid URL:
URL(string: "http://api-aws-eu-qa-1.abc-cde.com%E2%80%8B/v1/car-types/manufacturer?page=0&pageSize=10&wa_key=abc-cde-efg-44ccd99")
=> Optional(http://api-aws-eu-qa-1.abc-cde.com%E2%80%8B/v1/car-types/manufacturer?page=0&pageSize=10&wa_key=abc-cde-efg-44ccd99)
However, there is no such host as api-aws-eu-qa-1.abc-cde.com%E2%80%8B, so you should expect the actual connection to fail.
I expect that whatever is generating your URL strings has a bug.
If you are having trouble creating the URL itself (if URL(string:) return nil, then I expect this is not your actual URL string.
If you construct an URLComponents, the results are correct but may be slightly misleading:
URLComponents(string: "http://api-aws-eu-qa-1.abc-cde.com%E2%80%8B/v1/car-types/manufacturer?page=0&pageSize=10&wa_key=abc-cde-efg-44ccd99")?.host
Optional("api-aws-eu-qa-1.abc-cde.com")
While this looks like "api-aws-eu-qa-1.abc-cde.com", the string actually has a ZERO WIDTH SPACE at the end, which is invisible (but still part of the host field, which will correctly fail if you try to connect to it).

Related

Convert Postman GET curl to swift url session request

I am having trouble converting the following curl to a url request in swift.
curl --location --request GET 'https://p52.pocket52.com/apis/v1?p={%22x%22:%22images%22,%22pl%22:{}}'
I Tried the following way, but I got Unexpectedly found nil while unwrapping an Optional value error
var request = URLRequest(url: URL(string: "https://p52.pocket52.com/apis/v1?p={%22x%22:%22images%22,%22pl%22:{}}")!,timeoutInterval: Double.infinity)
request.httpMethod = "GET"
I tried with the solution present in this link Converting curl to URL request in Swift
but this is a POST curl it doesn't works for GET curl, Since GET request should not contains a body.
Let me define it more clearly, Basically I need to frame the following GET request.
https://p52.xxxx.com/apis/v1?p={"x":"images","pl":""}
We can achieve it by attaching a swift dictionary for a URLComponent part but, hear I am having a nested dictionary that's where I am facing difficulty.
You can follow this answer like #Turo suggested and build your URL using URLComponents, like so:
var components = URLComponents(string: "https://p52.pocket52.com/apis/v1")
components?.queryItems = [
URLQueryItem(name: "p", value: #"{"x": "images", "pl" : ""}"#)
]
Then use the url property of URLComponents to compose your URLRequest:
guard let url = components?.url else { return }
var request = URLRequest(url: url)
request.httpMethod = "GET"

Converting payload of NFC tag to URL adds extra characters to URL and makes it invalid address

I am trying this code and my desired URL is www.tapaway.com.au but what I am getting is https://%02tapaway.com.au. I have write the first URL www.tapaway.com.au on my NFC tag so whenever someone scans the tag it opens my webpage. My code is
func readerSession(_ session: NFCNDEFReaderSession, didDetectNDEFs messages: [NFCNDEFMessage]) {
var result = ""
for payload in messages[0].records{
print("-> \(payload)") //Prints the Entire NFC Payload on the Tag.
result += String.init(data: payload.payload, encoding: .utf8) ?? ""
}
DispatchQueue.main.async {
var components = URLComponents()
components.scheme = "https"
components.host = "\(result)"
components.path = "/"
let url = components.url
print(url)
UIApplication.shared.open(url!)
}
}
So a URL is stored in an encoded form in NDEF records to save space.
The %02 is the code for the URI Identifier, "https://www." in this case
The tapaway.com.au is the URI payload
So when correctly decode the URL is "https://www.tapaway.com.au" to which you would be adding "https" on the front again.
So you need to decode the payload correctly before you can use it as a URL.
The 1st byte is the URI Identifier.
All other bytes are the shortened URL
See the Specification document for this type of NDEF record at https://github.com/haldean/ndef/blob/master/docs/NFCForum-TS-RTD_URI_1.0.pdf
It seems there is a convenience function for this
https://developer.apple.com/documentation/corenfc/nfcndefpayload/3153117-wellknowntypeuripayload
so probably (I'm not a swift programmer)
var url = payload.wellKnownTypeURIPayload()

Issue deep linking to MS Excel from iOS app

I am trying to open an Excel document that is located on a server. I wrote the following code but it always returns false for UIApplication.shared.canOpenURL(url as URL)
I think I am missing some requirement for deep linking to Excel. Why is iOS not able to understand ms-excel:ofe|u| format?
#objc static func openExcel() {
let originalString = "http://s000.tinyupload.com/download.php?file_id=23290165129849240725&t=2329016512984924072514118"
let encodedString = originalString.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)
let encodedURLString = "ms-excel:ofe|u|" + encodedString! + "|n|TestDoc.xlsx|a|App"
if let url = NSURL(string: encodedURLString),
UIApplication.shared.canOpenURL(url as URL) {
UIApplication.shared.openURL(url as URL)
} else if let itunesUrl = NSURL(string: "https://itunes.apple.com/us/app/microsoft-excel/id586683407?mt=8&uo=4"), UIApplication.shared.canOpenURL(itunesUrl as URL) {
UIApplication.shared.openURL(itunesUrl as URL)
}
}
I have analyzed your code and found some mistakes. First, your URL was redirecting to somewhere, as per Microsoft documentation it can't handle redirecting URL's
The URL has to be encoded and must be a direct link to the file (not a
redirect). If the URL is in a format that Office cannot handle, or the
download simply fails, Office will not return the user to the invoking
application.
Here is Microsoft Documentation Link
The second mistake was you are only encoding the URL string containing site URL, you should consider the part after the scheme ms-excel: as a URL and should be encoded.
Because of improper encoding the let url = URL(string: encodedURLString) results nil that's why it is not working as expected.
Here is an example working code:
#objc static func openExcel() {
//replace the below url with yours. may be this one dosen't work
let originalString = "ofe|u|https://pgcconline.blackboard.com/webapps/dur-browserCheck-bb_bb60/samples/sample.xlsx"
let encodedString = originalString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)
let encodedURLString = "ms-excel:" + encodedString!
if let url = URL(string: encodedURLString),
UIApplication.shared.canOpenURL(url) {
UIApplication.shared.openURL(url)
} else if let itunesUrl = NSURL(string: "https://itunes.apple.com/us/app/microsoft-excel/id586683407?mt=8&uo=4"), UIApplication.shared.canOpenURL(itunesUrl as URL) {
UIApplication.shared.openURL(itunesUrl as URL)
}
}
Note: From iOS 9 you must whitelist any URL schemes your App wants to query in Info.plist under the LSApplicationQueriesSchemes key (an array of strings):
For example in our case:
When i try to open the URL in the question above I get redirected to this URL, so my guess would be that your code is fine, it just might be that your excel file you're trying to open is really an HTML page since tinyupload apparently blocks direct links to the files.
Maybe try opening a direct excel file download link, https://pgcconline.blackboard.com/webapps/dur-browserCheck-bb_bb60/samples/sample.xlsx (it was the first google result for 'xlsx file sample download')

Set Cookies for URL Request

Currently I have an iOS app that pulls prices and data from websites. So far its been working well, but I want to make it more accurate. To do so, I need to set the cookies for the URL request that I'm currently using String(contentsOf: _) for.
Current Process
let requestUrl: URL = URL(string: "http://www.samsclub.com/sams/search/searchResults.jsp?searchTerm=Apple")!
var content: String?
do {
content = try String(contentsOf: requestUrl)
} catch {
print("Error while converting an NSURL to String: \(error)")
}
if content != "" {
// I do things with the content of the requestUrl...
}
Could Use?
I thought that maybe I should use Alamofire instead to pull those website, and then parse the data.
I need to set the cookie that changes the store number to search, but have been unable to find a way to do so. Bellow is the code I have for pulling the websites data without setting a cookie.
let requestUrl: String = "http://www.samsclub.com/sams/search/searchResults.jsp?searchTerm=Apple"
Alamofire.request(requestUrl, method: .post).responseString { response in
if let content: String = response.result.value {
// I do things with the content of the requestUrl...
}
}
Other Claims
I have found many different ways to set cookies through Alamofire that don't work, but if Alamofire isn't the way to do it, please inform me. I really need this to work, and I'm open to any and every suggestion.
It took four weeks to the day, but I figured it out! URLRequest and Alamofire were my glorious answers!
Create the URL to call.
let requestUrl: String = "http://www.samsclub.com/sams/search/searchResults.jsp?searchTerm=Apple"
Next make the URLRequest with the URL string, and set its http method.
var urlRequest = URLRequest(url: requestUrl)
urlRequest.httpMethod = "POST"
Then set the cookies for the URLRequest.
urlRequest.setValue("myPreferredClub=4969", forHTTPHeaderField: "Cookie")
urlRequest.httpShouldHandleCookies = true
Finally send the URLRequest with Alamofire, and use the response data in whatever way I wish.
Alamofire.request(urlRequest).responseString { response in
if let content: String = response.result.value {
// I do things with the content of the urlRequest...
}
}

How to get a MS Translator access token from Swift 3?

I am trying to work with a MS Translator API from Swift 3 (right now playing in playgrounds, but the target platform is iOS). However, I got stuck when I was trying to get an access token for OAuth2. I have following code (I tried to port the code from example at Obtaining an access token):
let clientId = "id".addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!
let clientSecret = "secret".addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!
let scope = "http://api.microsofttranslator.com".addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!
let translatorAccessURI = "https://datamarket.accesscontrol.windows.net/v2/OAuth2-13"
let requestDetails = "grant_type=client_credentials&client_id=\(clientId)&client_secret=\(clientSecret)&scope=\(scope)"
let postData = requestDetails.data(using: .ascii)!
let postLength = postData.count
var request = URLRequest(url: URL(string: translatorAccessURI)!)
request.httpMethod = "POST"
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.setValue("\(postLength)", forHTTPHeaderField: "Content-Length")
request.httpBody = postData
URLSession.shared.dataTask(with: webRequest) { (returnedData, response, error) in
let data = String(data: returnedData!, encoding: .ascii)
print(data)
print("**************")
print(response)
print("**************")
print(error)
}.resume()
Of course, I used a valid clientId and a valid clientSecret.
Now the callback prints following information. First, the returnedData contain a message that the request was invalid, along with a following message:
"ACS90004: The request is not properly formatted."
Second, the response comes with a 400 code (which fits the fact that the request is not properly formatted).
Third, the error is nil.
Now I was testing the call using Postman, and when I used the same URI, and put the requestDetails string as a raw body message (I added the Content-Type header manually), I got the same response. However, when I changed the body type in Postman UI to application/x-www-form-urlencoded and typed in the request details as key value pairs through its UI, the call succeeded. Now it seems that I am doing something wrong with the message formatting, or maybe even something bad with the Swift URLRequest/URLSession API, however, I cannot get a hold on to what. Can somebody help me out, please? Thanks.
OK, so after some more desperate googling and experimenting I have found my error. For the future generations:
The problem resided in encoding the parameters in the body of the PUT http request. Instead of:
let scope = "http://api.microsofttranslator.com"
.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!
I have to use the following:
let scope = "http://api.microsofttranslator.com"
.addingPercentEncoding(withAllowedCharacters:
CharacterSet(charactersIn: ";/?:#&=$+{}<>,").inverted)!
Seems that the API (or the HTTP protocol, I am not an expert in this) have problems with / and : characters in the request body. I have to give credit to Studiosus' answer on Polyglot issue report.

Resources