Siri Shortcut Intent API call says URL is nil, but its not - ios

Here is the code that I am dealing with:
let url = "https://www.host.com/url/\(intent.cardInfo!)"
print(url)
let url2 = URL(string: url)! // this is nil??
let request = NSMutableURLRequest(url: url2)
Below is an image showing that this value is not nil (you can see that in the console). I get the value after the Siri intent. This is inside of the IntentHandler. All of the code is below.
class SoldForAppIntentHandler : NSObject, SoldForAppIntentHandling {
func handle(intent: SoldForAppIntent, completion: #escaping (SoldForAppIntentResponse) -> Void) {
print(intent.sport!)
print(intent.cardInfo!)
print(intent.cardNumber!)
let url = "https://www.host.com/url/\(intent.cardInfo!)"
print(url)
let url2 = URL(string: url)!
let request = NSMutableURLRequest(url: url2)
request.httpMethod = "GET"
let postString = ""
request.httpBody = postString.data(using: String.Encoding.utf8)
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
let task = URLSession.shared.dataTask(with: request as URLRequest) {
data, response, error in
if error != nil {
print("error=\(error)")
return
}
let responseString = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
do {
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary
//print(json!)
let response = json!["value"] as! String
} catch {
print(" error adding tap search to db:\(error)")
}
print()
}
task.resume()
completion(SoldForAppIntentResponse.success(response: "\n\nSold For will look up \(intent.sport!) \(intent.cardInfo!) \(intent.cardNumber!)"))
}

Problem is actually url2 itself, because the string https://www.host.com/url/1986 fleer 57 Michael Jordan PSA 10 cannot be properly converted into URL object.
You can try something like this:
if let url = "https://www.host.com/url/\(intent.cardInfo!)".addingPercentEncoding(withAllowedCharacters: .urlHostAllowed) {
let url2 = URL(string: url)!
}

Related

Swift - JSON data wont display in UITableview

I am trying to retrieve data from a server. I can display my data in the console.
I'm trying to display it in a UITableview but nothing happens.
I tried to create a local JSON file and I am able to display it, but when coming from the server it wont work.
let newUrl = URL(string: urlGetNotifications)
let configuration = URLSessionConfiguration.default
var session = URLSession.shared
var request = URLRequest(url: newUrl!)
session = URLSession(configuration: configuration)
request.httpMethod = "GET"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
request.setValue(authkeyFCM, forHTTPHeaderField: "auth-key")
request.setValue(tokenFCM.string(forKey: "tokenFCM"), forHTTPHeaderField: "token")
let task = session.dataTask(with: request as URLRequest, completionHandler: { data, response, error in
DispatchQueue.main.async {
guard let j = newUrl
else{
print("data not found")
return
}
guard let d = try? Data(contentsOf: j)
else { print("failed")
return
}
guard let rootJSON = try? JSONSerialization.jsonObject(with: d, options: [])
else{ print("failedh")
return
}
if let data = data, let dataString = String(data: data, encoding: .utf8) {
if let JSON = rootJSON as? [String: Any] {
print("data: \(dataString)")
guard let jsonArray = JSON["data"] as? [[String: Any]] else {
return
}
print(jsonArray)
let name = jsonArray[0]["type"] as? String
print(name ?? "NA")
print(jsonArray.last!["created_at"] as? String as Any)
self.notificationList = jsonArray.compactMap{return NotificationData($0)}
self.tableView.reloadData()
}
}
}
})
task.resume()
create a variable for the URL and create struct contain the all param
in the main add variable of type the struck then start fetch the data
var users: [User]() = []
func fetchUsers(using url: String){
let url = URL(string: url)!
let _ = URLSession.shared.dataTask(with: url){ (data,response,error)
in
guard let data = data else {return}
do{
let userFetch = try JSONDecoder().decode([Post].self, from: data) // decode * ( Codable )
self.users = userFetch
self.load(with: userFetch)
self.userCollection = userFetch
DispatchQueue.main.async {
self.collectionView.reloadData()
}
} catch{
print("error loading data cause: \(error)")
}
}.resume()
}
I figured it out
This one works
let newUrl = URL(string: urlGetNotifications)
let configuration = URLSessionConfiguration.default
var session = URLSession.shared
var request = URLRequest(url: newUrl!)
session = URLSession(configuration: configuration)
request.httpMethod = "GET"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
request.setValue(authkeyFCM, forHTTPHeaderField: "auth-key")
request.setValue(tokenFCM.string(forKey: "tokenFCM"), forHTTPHeaderField: "token")
let task = session.dataTask(with: request as URLRequest, completionHandler: { data, response, error in
DispatchQueue.main.async {
do {
let json = try JSONSerialization.jsonObject(with: data!, options: [])
//self.showSpinner(onView: self.view)
print("The Response is : ",json)
if let data = data, let dataString = String(data: data, encoding: .utf8) {
if let JSON = json as? [String: Any] {
print("dumaan ba dito")
print("data: \(dataString)")
guard let jsonArray = JSON["data"] as? [[String: Any]] else {
return
}
print(jsonArray)
let name = jsonArray[0]["type"] as? String
print(name ?? "NA")
print(jsonArray.last!["created_at"] as? String as Any)
self.notificationList = jsonArray.compactMap{return NotificationData($0)}
self.tableView.reloadData()
}
}
} catch {
print("JSON error: \(error.localizedDescription)")
}
} // end
})
task.resume()

Why not getting response from one URL?

I am using URLSession. I am not receiving any error or response.
It works with one url. However it does not work with one another.
I have also tried percentencoding. But it doesn't work too.
The code is below
let urlString = "https://stark-spire-93433.herokuapp.com/json"//This is not working
//let urlString = "https://jsonplaceholder.typicode.com/todos"//This is working
let config = URLSessionConfiguration.default
let session = URLSession(configuration: config)//URLSession.shared
var request = URLRequest(url: URL(string:urlString)!)
request.httpMethod = "GET"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = try? JSONSerialization.data(withJSONObject: [], options: [])
let task = session.dataTask(with: request, completionHandler: { data, response, error -> Void in
print("response---",response)
print("error--",error)
if data != nil {
let json = try? JSONSerialization.jsonObject(with: data!)
print("JSOn",json)
} else {
print("error data is nil")
}
})
task.resume()
Too cumbersome code.
This is sufficient
let url = URL(string:"https://stark-spire-93433.herokuapp.com/json")!
let task = URLSession.shared.dataTask(with: url) { data, response, error in
guard let data = data else { print(error!); return }
do {
let json = try JSONSerialization.jsonObject(with: data)
print("JSOn",json)
} catch {
print(error)
}
}
task.resume()

Swift HTTP Post Request returns HTML of site instead of JSON response

I am trying to reach a site that should take the username and password given and return a JSON which contains information stating whether or not the login data provided was valid or not.
However, all I'm getting back is the site's HTML code instead of a response. I've tried the request with the same parameters on https://www.hurl.it/ and have gotten the correct response so that does not seem to be the issue.
I use the following code:
private func uploadToAPI(username: String, password: String) {
guard let url = URL(string: "http://api.foo.com/login.php"),
let encodedUsername = username.addingPercentEncoding(withAllowedCharacters: CharacterSet.alphanumerics),
let encodedPassword = password.addingPercentEncoding(withAllowedCharacters: CharacterSet.alphanumerics) else {
self.loginButton.isLoading = false
return
}
let httpBodyParameters = ["user": encodedUsername, "password": encodedPassword, "client": "ios", "version": "5"]
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = try? JSONSerialization.data(withJSONObject: httpBodyParameters, options: JSONSerialization.WritingOptions.prettyPrinted)
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("application/json", forHTTPHeaderField: "Accept")
URLSession.shared.dataTask(with: request) { (data, response, error) in
if let response = response {
print(response.mimeType) // Prints "text/html"
}
if let data = data {
print(try? JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.allowFragments)) // Prints nil
print(String(data: data, encoding: String.Encoding.utf8)) // Prints the site's HTML
}
}.resume()
}
I fail to see where the issue is. I've also tried not setting the HTTP headers but that makes no difference. Anyone got any ideas?
It seems like not setting the HTTP header fields and using a string literal instead of a Dictionary as HTTP body data did it for me.
For anyone interested this is the code that now receives the expected response:
guard let url = URL(string: "http://api.foo.com/login.php?"),
let encodedUsername = username.addingPercentEncoding(withAllowedCharacters: CharacterSet.alphanumerics),
let encodedPassword = password.addingPercentEncoding(withAllowedCharacters: CharacterSet.alphanumerics) else {
if let delegate = self.delegate {
delegate.viewModelDidRejectLogin(self)
}
return
}
let httpBodyString = "user=\(encodedUsername)&password=\(encodedPassword)&client=ios&version=5"
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = httpBodyString.data(using: String.Encoding.utf8)
URLSession.shared.dataTask(with: request) { (data, response, error) in
guard let data = data, error == nil else {
print(error)
return
}
do {
if let json = try JSONSerialization.jsonObject(with: data) as? [String : AnyObject] {
self.readLoginResponse(json)
}
} catch {
print(error)
}
}.resume()

Spotify API Authorization Error (Swift)

I've made a little App in Swift where a user can search the Spotify database for songs. I am using the Web API Console > Search for an Item. My problem is the new OAuth system where you have to sign-in and all that stuff. My authorization is ok, but when I'm trying to get an access token with the following code, it's returning me the following error: {"error":"server_error","error_description":"Unexpected status: 400"}. My code is:
let keys = "<MY_APPLICATION_KEYS>"
let url = NSURL(string: "https://accounts.spotify.com/api/token")
let session = URLSession.shared
let request = NSMutableURLRequest(url: url! as URL)
request.httpMethod = "POST"
request.setValue("Basic \(keys)", forHTTPHeaderField: "Authorization")
request.setValue("client_credentials", forHTTPHeaderField: "grant_type")
let task = session.dataTask(with: request as URLRequest) { (data, response, error) in
guard let _: Data = data, let _: URLResponse = response, error == nil else {
print(error!)
return
}
let dataString = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
print("Data: \(dataString!)")
self.parseData(JSONData: data!)
}
task.resume()
}
var accessToken = ""
func parseData(JSONData : Data) {
do {
var readableJSON = try JSONSerialization.jsonObject(with: JSONData, options: .mutableContainers) as! JSONStandard
if let token = readableJSON["access_token"] as? String {
accessToken = token
}
print("Access Token: \(accessToken)")
updateTokenInFirebase()
}
catch{
print(error)
}
Any help would be very appreciated, thank you very much in advance!
Documentation of the Web API: Web API Link
I am using on the Client Credentials Flow the first method.
I know it's been ~1 year since you posted this but I had the same issue and after a few tries was able to get it. You can test this in Playground.
import Foundation
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
if let url = URL(string: "https://accounts.spotify.com/api/token") {
var postRequest = URLRequest(url: url)
postRequest.httpMethod = "POST"
let bodyParams = "grant_type=client_credentials"
postRequest.httpBody = bodyParams.data(using: String.Encoding.ascii, allowLossyConversion: true)
let id = "your client id"
let secret = "your secret"
let combined = "\(id):\(secret)"
let combo = "\(id):\(secret)".toBase64()
postRequest.addValue("Basic \(combo)", forHTTPHeaderField: "Authorization")
let task = URLSession.shared.dataTask(with: postRequest) { (data, response, error) in
guard let data = data else {
return
}
print(String(data: data, encoding: String.Encoding.utf8)!)
}
task.resume()
}
extension String {
func fromBase64() -> String? {
guard let data = Data(base64Encoded: self) else {
return nil
}
return String(data: data, encoding: .utf8)
}
func toBase64() -> String {
return Data(self.utf8).base64EncodedString()
}
}
I know this is really late, but the issue is with this line:
request.setValue("client_credentials", forHTTPHeaderField: "grant_type")
According to the authorization guide, this should be in the body of the request, not the headers.

Swift iOS HTTP request post json

I want to make a HTTP request to a server but I have troubles parsing my data to JSON.
This is my code:
let dic = ["interest":["category":"Viajes","value":"Mexico"],"metadata":["version":"0.1","count":1]]
do{
let jsonData = try NSJSONSerialization.dataWithJSONObject(dic, options: NSJSONWritingOptions())
let url:NSURL = NSURL(string: "http://ip/interests")!
let session = NSURLSession.sharedSession()
let request = NSMutableURLRequest(URL: url)
request.HTTPMethod = "POST"
request.cachePolicy = NSURLRequestCachePolicy.ReloadIgnoringCacheData
//let paramString = ""
//request.HTTPBody = paramString.dataUsingEncoding(NSUTF8StringEncoding)
request.HTTPBody = jsonData
let dataString = NSString(data: jsonData, encoding: NSUTF8StringEncoding)
print(dataString)
let task = session.dataTaskWithRequest(request) {
(
let data, let response, let error) in
guard let _:NSData = data, let _:NSURLResponse = response where error == nil else {
print(error)
return
}
print(response?.description)
}
task.resume()
}catch let error as NSError {
print(error)
return
}
The server catch :
{ '{"interest":{"category":"Viajes","value":"Mexico"},"metadata":{"count":1,"version":"0.1"}}': '' }
What I want:
{"interest":{"category":"Viajes","value":"Mexico"},"metadata":{"count":1,"version":"0.1"}}
Anybody knows how to fix it?

Resources