Or parameterized API call crashing in Swift - ios

I am making a call to an API where I want have status equal to final or in progress. Here is the call I am using:
let request = NSMutableURLRequest(url: NSURL(string: "https://sportspage-feeds.p.rapidapi.com/games?status=in%20progress||status=final")! as URL,
cachePolicy: .useProtocolCachePolicy,
timeoutInterval: 10.0)
It works perfectly in Postman, but when trying it in my app it is crashing with this error:
Fatal error: Unexpectedly found nil while unwrapping an Optional value: file
Is there a different way to use or in Swift?

You have manually percent encoded the space, but you have not percent encoded the two pipe characters. As a result the initialiser for NSURL fails, returning nil. Since you have force-unwrapped this value, your app then crashes.
You can use the function .addingPercentEncoding(withAllowedCharacters:) to percent encode a string appropriately and then create a URL.
Both percent encoding a string and creating a URL can fail, so these operations return an optional. You should use conditional unwrapping rather than force unwrapping to avoid crashes if these operations fail.
Many NS classes have bridged Swift equivalents including URLRequest for NSURLRequest and URL for NSURL. Idiomatic Swift eschews the use of an NS class when a Swift equivalent exists.
Use something like
if let urlStr = "https://sportspage-feeds.p.rapidapi.com/games?status=in progress||status=final".addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed), let url = URL(urlStr) {
let request = URLRequest(url, timeoutInterval: 10)
...
}
As Matt pointed out in a comment, the correct way to construct a URL in iOS is to use URLComponents. This allows you to specify each component of the URL independently and not worry about things like manual percent encoding.
The use of URLComponents is particularly important where you collect input from the user and they could attempt to manipulate the resulting URL string.
var components = URLComponents()
components.scheme = "https"
components.host = "sportspage-feeds.p.rapidapi.com"
components.path = "/games"
components.queryItems = [(URLQueryItem(name:"status", value:"in progress||status=final"))]
if let url = components.url {
let request = URLRequest(url, timeoutInterval: 10)
...
}

Related

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")
}

Can iOS URL support unicode characters within top level domain?

I'm building an iOS app that takes urls as input.
Unicode characters are valid for a tld but when I instantiate a valid URL that contains unicode characters NSURL returns nil.
Is this even possible?
swift eg.
URL(string: "http://➡.ws/䨹")
How to use special characters in URL (Swift 3) :
let myUrl = "http://➡.ws/䨹" as String
let url = URL(string: myUrl) // nil here .. problem !
if let encoded = myUrl.addingPercentEncoding(withAllowedCharacters: .urlFragmentAllowed){
let urlencoded = URL(string: encoded) // "http://%E2%9E%A1.ws/%E4%A8%B9" here :) no problem ^^
}

How to POST integer request to server in swift ios?

let theRequest = NSMutableURLRequest(URL: url!)
theRequest.HTTPMethod = "POST"
let parameters = ["otp":firstDigit.text!,"otp":secondDigit.text!,"otp":thirdDigit.text!,"otp":fourthDigit.text!] as Dictionary<String,String>
How to add parameters to pass numbers in to the server side. There is only one field in the server side and I have to pass 4 integers using four different text fields. How can I pass it? Basically I am passing an OTP(One time password with four digits)
First make the OTP variable like this:-
var otpText:String= firstDigit.text + secondDigit.text +thirdDigit.text+fourthDigit.text
then form the parameter:-
let parameters : NSDictionary =["otp":otpText]
Have you checked out the property HTTPBody: https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSMutableURLRequest_Class/#//apple_ref/occ/instp/NSMutableURLRequest/HTTPBody
Not compiled myself, but would be something like:
let otp = firstDigit.text + secondDigit.text+thirdDigit.text+fourthDigit.text
let json = [ "OTP" : otp ]
let jsonData = NSJSONSerialization.dataWithJSONObject(json, options: NSJSONWritingOptions.allZeros, error: nil)
theRequest.HTTPBody = jsonData
What this code does:
Concatenate your text values to make a string
Create a dictionary (JSON object) with the key your server expected
and the value of the concatenated string
Convert that dictionary to NSData as expected by the HTTPBody property
Set the HTTPBody property on your NSMutableURLRequest
Also checkout out https://github.com/AFNetworking/AFNetworking. It makes it super simple to handle HTTP requests using iOS.

Cyrillic symbols in URL

App crashes with following url:
let jsonUrl = "http://api.com/алматы/events"
let session = NSURLSession.sharedSession()
let shotsUrl = NSURL(string: jsonUrl)
let task = session.dataTaskWithURL(shotsUrl!)
Log:
fatal error: unexpectedly found nil while unwrapping an Optional value
It's because of cyrillic symbols in url. How can I solve this issue. Thanks for your help!
Swift 4
Using String Extension
Create a swift file named String+Extension.swift and paste this code
import UIKit
extension String{
var encodeUrl : String
{
return self.addingPercentEncoding(withAllowedCharacters: NSCharacterSet.urlQueryAllowed)!
}
var decodeUrl : String
{
return self.removingPercentEncoding!
}
}
and Use it like so: (sample according to question):
"http://api.com/алматы/events".encodeUrl
Try this:
let encodedUrl = jsonUrl.stringByAddingPercentEncodingWithAllowedCharacters(URLQueryAllowedCharacterSet)
Something like this:
let apiHost = "http://api.com/"
let apiPath = "алматы/events"
let escapedPath = apiPath.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLHostAllowedCharacterSet())
let url = NSURL(string: "\(apiHost)\(escapedPath!)")
Obviously you should do something smarter than just force unwrap escapedPath.
Using the Wikipedia page for Swift as an example:
https://ru.wikipedia.org/wiki/Swift_(язык_программирования)
Becomes:
https://ru.wikipedia.org/wiki/Swift_(%D1%8F%D0%B7%D1%8B%D0%BA_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F)
Which when pasted into the browser takes you to the right page (and most browsers will conveniently render the UFT-8 characters for you).
Non-ASCII characters (and many special characters) need to be escaped in a URL. Chrome and other browser do it automatically. And they unescape the URLs in the address bar for a nicer display.
So if you have a static URL, just paste it into the adressbar, press enter, selected the URL again, copy and paste it to your app:
So instead of:
let jsonUrl = "http://api.com/алматы/events"
You'll get:
let jsonUrl = "http://api.com/%D0%B0%D0%BB%D0%BC%D0%B0%D1%82%D1%8B/events"
Try stringByAddingPercentEncodingWithAllowedCharacters: defined on NSString. You may see people suggesting stringByAddingPercentEscapesUsingEncoding:, but that method is deprecated in iOS 9.
There are also a few predefined NSCharacterSets in Foundation, such as URLHostAllowedCharacterSet and URLPathAllowedCharacterSet. Therefore, if you really have to parse the unescaped URL in code (using preprocessed URLs, mentioned in the accepted answer, is usually a much better idea), you can write a helper method like this:
import Foundation
func url(scheme scheme: String, host: String, path: String) -> NSURL? {
let components = NSURLComponents()
components.scheme = scheme
components.host = host.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLHostAllowedCharacterSet())
components.path = path.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLPathAllowedCharacterSet())
return components.URL
}
// evaluates to http://api.com/%25D0%25B0%25D0%25BB%25D0%25BC%25D0%25B0%25D1%2582%25D1%258B/events
url(scheme: "http", host: "api.com", path: "/алматы/events")
Note that the above documentation mentions that
This method is intended to percent-encode an URL component or subcomponent string, NOT an entire URL string.
That's because according RFC 3986, not all parts of an URL can be percent-encoded (e.g. scheme - http/https/etc.)
in xamarin:
var uri = new Uri (url);
var nsurl = new NSUrl (uri.GetComponents (UriComponents.HttpRequestUrl, UriFormat.UriEscaped));
UIApplication.SharedApplication.OpenUrl (nsurl);
URLs cannot contain Cyrillic characters. There are standards how to translate Cyrillic characters into valid URLs - you might find something if you search for "Punicode" (the P is intentional).

Resources