I built a backend API to my app in Laravel (PHP). The return from the method I am calling (create user) is:
{"success":true,"userid":"23"}
but when accessing userid in Swift it returns a null? It can access the success variable.
Here is the code for my request:
// create the user
var request = NSMutableURLRequest(URL: NSURL(string: "http://localhost/laravel/myapi/public/createUser"))
var session = NSURLSession.sharedSession()
request.HTTPMethod = "POST"
var params = ["username":txtUsername.text, "email":txtEmail.text, "password":txtPassword.text] as Dictionary
var err: NSError?
request.HTTPBody = NSJSONSerialization.dataWithJSONObject(params, options: nil, error: &err)
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
var task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
// println("Response: \(response)")
var strData = NSString(data: data, encoding: NSUTF8StringEncoding)
println("Body: \(strData)")
var err: NSError?
let json = NSJSONSerialization.JSONObjectWithData(data, options: .AllowFragments & .MutableLeaves, error: &err) as NSDictionary
if(err) {
println(err!.localizedDescription)
}
else {
var success = json["success"] as? Int
if(success == 1) {
var id = json["userid"] as? Int
self.lblTaken.text = "\(id)"
}
}
})
task.resume()
the println("Body: \(strData)") prints out:
Body: {"success":true,"userid":"23"}
But when trying to access the userid variable, it returns nil
Am I doing something wrong when trying to access the userid?
UPDATE
if I print out:
println(json.valueForKey("userid"))
it prints out the userid, but if I assign it to the variable, the variable returns a null still
The userId comes as a string. So, the problem is, you try to cast a string to an integer using as? and fail.
From Apple docs:
The as? operator performs a conditional cast of the expression to the specified type. The as? operator returns an optional of the specified type. At runtime, if the cast succeeds, the value of expression is wrapped in an optional and returned; otherwise, the value returned is nil. If casting to the specified type is guaranteed to fail, a compile-time error is raised. For example, casting to a type that’s neither a subclass or superclass of the type of the expression is an error.
Related
This code continues to give me an error handling message near the URLSession instantiation. I am confused with swift3 help please.
let myUrl = NSURL(string: "http://myURL.com/user")
let request = NSMutableURLRequest(url: myUrl! as URL)
request.httpMethod = "POST"
let postString = "email=\(userEmail)&password=\(userPassword)&username=\(userUsername)"
request.httpBody = postString.data(using: String.Encoding.utf8)
let task = URLSession.shared.dataTask(with: request as URLRequest)
{
(data: Data!, response: URLResponse!, error: Error!) in
if error != nil
{
print("error=\(error)")
return
}
var err: NSError?
do {
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary
if let parseJSON = json {
var resultValue:String = parseJSON["status"] as! String;
print("result: \(resultValue)");
The error I get is:
invalid conversion from throwing function of type '(Data?, URLResponse?, Error?) throws ->()' to non-throwing function type
I think the error means the following.
By default the function can throw, which is why it uses optionals for return values. Whenever the function throws, the optional values will be nil. However you remove the optional nil values using the exclamation mark operator.
You should read up on how to properly handle exceptions in Swift. Then you should be able to clean up your code and make it work correctly.
The error is misleading. Just omit the type annotations, they do more harm than good.
And use the native structs without the NS prefix:
let myUrl = URL(string: "http://myURL.com/user")!
var request = URLRequest(url: myUrl)
request.httpMethod = "POST"
let postString = "email=\(userEmail)&password=\(userPassword)&username=\(userUsername)"
request.httpBody = postString.data(using: .utf8)
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in ...
I am working on a student system project. All the server side things are done but the iOS client application is making some trouble.
I am trying to create a login page for the user and than check in the database whether the info is correct
Here is the code:
import Foundation
import UIKit
class LoginPage: UIViewController {
/*A reference to the username/student ID text field*/
#IBOutlet weak var idField: UITextField!
//A reference to the password field
#IBOutlet weak var passwordField: UITextField!
//Send the information from the text fields to the server
#IBAction func loginButtonTapped(_ sender: UIButton) {
//declare parameter as a dictionary which contains string as key and value combination.
var parameters = ["name": idField.text!, "password": passwordField.text!] as Dictionary<String, String>
//create the url with NSURL
let url = NSURL(string: "https://api.sis.kemoke.net")
//create the session object
var session = URLSession.sharedSession()
//now create the NSMutableRequest object using the url object
let request = NSMutableURLRequest(url: url! as URL)
request.httpMethod = "POST" //set http method as POST
var err: NSError?
request.HTTPBody = JSONSerialization.dataWithJSONObject(parameters, options: nil, error: &err) // pass dictionary to nsdata object and set it as request body
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
//create dataTask using the session object to send data to the server
var task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
println("Response: \(response)")
var strData = NSString(data: data, encoding: NSUTF8StringEncoding)
println("Body: \(strData)")
var err: NSError?
var json = NSJSONSerialization.JSONObjectWithData(data, options: .MutableLeaves, error: &err) as? NSDictionary
// Did the JSONObjectWithData constructor return an error? If so, log the error to the console
if(err != nil) {
println(err!.localizedDescription)
let jsonStr = NSString(data: data, encoding: NSUTF8StringEncoding)
println("Error could not parse JSON: '\(jsonStr)'")
}
else {
// The JSONObjectWithData constructor didn't return an error. But, we should still
// check and make sure that json has a value using optional binding.
if let parseJSON = json {
// Okay, the parsedJSON is here, let's get the value for 'success' out of it
var success = parseJSON["success"] as? Int
println("Succes: \(success)")
}
else {
// Woa, okay the json object was nil, something went worng. Maybe the server isn't running?
let jsonStr = NSString(data: data, encoding: NSUTF8StringEncoding)
println("Error could not parse JSON: \(jsonStr)")
}
}
})
task.resume()
}
}
For me this all looks good, but I am getting an error
"can not call function URLSession"
and
"Extra argument" for the error handler.
How do I fix this?
I really need a code for send and receive data from server with JSON, i find a really good code but it isn't compatible with iOS9.
#IBAction func submitAction(sender: AnyObject) {
//declare parameter as a dictionary which contains string as key and value combination.
var parameters = ["name": nametextField.text, "password": passwordTextField.text] as Dictionary<String, String>
//create the url with NSURL
let url = NSURL(string: "http://myServerName.com/api") //change the url
//create the session object
var session = NSURLSession.sharedSession()
//now create the NSMutableRequest object using the url object
let request = NSMutableURLRequest(URL: url!)
request.HTTPMethod = "POST" //set http method as POST
var err: NSError?
request.HTTPBody = NSJSONSerialization.dataWithJSONObject(parameters, options: nil, error: &err) // pass dictionary to nsdata object and set it as request body
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
//create dataTask using the session object to send data to the server
var task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
println("Response: \(response)")
var strData = NSString(data: data, encoding: NSUTF8StringEncoding)
println("Body: \(strData)")
var err: NSError?
var json = NSJSONSerialization.JSONObjectWithData(data, options: .MutableLeaves, error: &err) as? NSDictionary
// Did the JSONObjectWithData constructor return an error? If so, log the error to the console
if(err != nil) {
println(err!.localizedDescription)
let jsonStr = NSString(data: data, encoding: NSUTF8StringEncoding)
println("Error could not parse JSON: '\(jsonStr)'")
}
else {
// The JSONObjectWithData constructor didn't return an error. But, we should still
// check and make sure that json has a value using optional binding.
if let parseJSON = json {
// Okay, the parsedJSON is here, let's get the value for 'success' out of it
var success = parseJSON["success"] as? Int
println("Succes: \(success)")
}
else {
// Woa, okay the json object was nil, something went worng. Maybe the server isn't running?
let jsonStr = NSString(data: data, encoding: NSUTF8StringEncoding)
println("Error could not parse JSON: \(jsonStr)")
}
}
})
task.resume() }
Really thanks for the help
Swift syntax changed a little bit, but not significantly to break the whole code.
You will need to adjust few things like
println(err!.localizedDescription)
to
print(err!.localizedDescription)
Then your code will compile
Maybe have a look into the Alamofire Framework.
It really is making your life easier when it comes to handling HTTP requests.
Otherwise, as vadian suggested, check out the Swift 2 (do-try-catch) Errorhandling.
I have found a great tutorial Project from deege.
https://github.com/deege/deegeu-swift-rest-example
Here a breakdown of a HTTP request.
// Setup the session to make REST GET call. Notice the URL is https NOT http!! (if you need further assistance on how and why, let me know)
let endpoint: String = "https://yourAPI-Endpoint"
let session = NSURLSession.sharedSession()
let url = NSURL(string: endpoint)!
// Make the call and handle it in a completion handler
session.dataTaskWithURL(url, completionHandler: { ( data: NSData?, response: NSURLResponse?, error: NSError?) -> Void in
// Make sure we get an OK response
guard let realResponse = response as? NSHTTPURLResponse where
realResponse.statusCode == 200 else {
print("Not a 200 response")
return
}
// Read the JSON
do {
if let jsonString = NSString(data:data!, encoding: NSUTF8StringEncoding) {
// Print what we got from the call
print(jsonString)
// Parse the JSON
let jsonDictionary = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as! NSDictionary
let value = jsonDictionary["key"] as! String
}
} catch {
print("bad things happened")
}
}).resume()
The following curl works
curl -G -H "api_key: MYAPIKEY" https://api.semantics3.com/test/v1/products -d 'q={"upc":"70411576937"}'
However, upon trying to convert it to iOS I get the following error:
Error Domain=NSURLErrorDomain Code=-1005 "The network connection was lost." {NSErrorFailingURLStringKey=https://api.semantics3.com/test/v1/products,...}
I have attached my code below but I believe that my problem is the "q=" right before the json data that is being submitted to the URL. If so, what is this called and how do I put "q=" before my json data? I can't exactly tell though, due to iOS' unfaltering ability to provide us with unrelated error messages. Thank you.
var urlString = "https://api.semantics3.com/test/v1/products"
var request = NSMutableURLRequest(URL: NSURL(string: urlString)!)
var response: NSURLResponse?
var error: NSErrorPointer = nil
var reqText = ["upc": "70411576937"]
var err: NSError?
request.HTTPBody = NSJSONSerialization.dataWithJSONObject(reqText, options: nil, error: &err)
request.HTTPMethod = "GET"
request.addValue("MYAPIKEY", forHTTPHeaderField: "api_key")
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
var session = NSURLSession.sharedSession()
var task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
var strData = NSString(data: data, encoding: NSUTF8StringEncoding)
if(err != nil) {
println(err!.localizedDescription)
}
else {
//this is where the error is printed
println(error)
var parseError : NSError?
// parse data
let unparsedArray: AnyObject? = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.AllowFragments, error: &parseError)
println(parseError)
if let resp = unparsedArray as? NSDictionary {
println(resp)
}
}
})
task.resume()
Body is not used in GET http methods. Use the following code to concat your params:
extension String {
/// Percent escape value to be added to a URL query value as specified in RFC 3986
///
/// This percent-escapes all characters besize the alphanumeric character set and "-", ".", "_", and "~".
///
/// http://www.ietf.org/rfc/rfc3986.txt
///
/// :returns: Return precent escaped string.
func stringByAddingPercentEncodingForURLQueryValue() -> String? {
let characterSet = NSMutableCharacterSet.alphanumericCharacterSet()
characterSet.addCharactersInString("-._~")
return self.stringByAddingPercentEncodingWithAllowedCharacters(characterSet)
}
}
extension Dictionary {
/// Build string representation of HTTP parameter dictionary of keys and objects
///
/// This percent escapes in compliance with RFC 3986
///
/// http://www.ietf.org/rfc/rfc3986.txt
///
/// :returns: String representation in the form of key1=value1&key2=value2 where the keys and values are percent escaped
func stringFromHttpParameters() -> String {
let parameterArray = map(self) { (key, value) -> String in
let percentEscapedKey = (key as! String).stringByAddingPercentEncodingForURLQueryValue()!
let percentEscapedValue = (value as! String).stringByAddingPercentEncodingForURLQueryValue()!
return "\(percentEscapedKey)=\(percentEscapedValue)"
}
return join("&", parameterArray)
}
}
var urlString = "https://api.semantics3.com/test/v1/products"
var reqText = ["upc": "70411576937"]
var err: NSError?
let parameterString = reqText.stringFromHttpParameters()
let requestURL = NSURL(string:"\(urlString)?\(parameterString)")!
var request = NSMutableURLRequest(URL: NSURL(string: urlString)!)
var response: NSURLResponse?
var error: NSError?
request.HTTPMethod = "GET"
request.addValue("MYAPIKEY", forHTTPHeaderField: "api_key")
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
var session = NSURLSession.sharedSession()
PARTIAL EDIT: SWIFT 2.1 (updated)
extension Dictionary {
func stringFromHttpParameters() -> String {
let parameterArray = self.map { (key, value) -> String in
let percentEscapedKey = (key as! String).stringByAddingPercentEncodingForURLQueryValue()!
let percentEscapedValue = (value as! String).stringByAddingPercentEncodingForURLQueryValue()!
return "\(percentEscapedKey)=\(percentEscapedValue)"
}
return parameterArray.joinWithSeparator("&")
}
}
Convert your JSON to a string, prepend the q= to this, then convert the resulting string to Data before assigning it to the request's HTTPBody.
Something like this perhaps:
let array = [ "one", "two" ]
let data = NSJSONSerialization.dataWithJSONObject(array, options: nil, error: nil)
let body= "q=" + NSString(data: data!, encoding: NSUTF8StringEncoding)
request.HTTPBody = body.dataUsingEncoding(NSUTF8StringEncoding)
I have a request:
let authRequest = NSMutableURLRequest(URL: self.authUrl!)
authRequest.HTTPMethod = "POST"
var params = ["email": "me#email.com", "password": "password"] as Dictionary<String, String>
var err: NSError?
authRequest.HTTPBody = NSJSONSerialization.dataWithJSONObject(params, options: nil, error: &err)
authRequest.addValue("application/json", forHTTPHeaderField: "Content-Type")
authRequest.addValue("application/json", forHTTPHeaderField: "Accept")
let authSession = NSURLSession.sharedSession().dataTaskWithRequest(authRequest, completionHandler: {data, response, error -> Void in
println("Response: \(response)")
var strData = NSString(data: data, encoding: NSUTF8StringEncoding)
println("Body: \(strData)")
var err: NSError?
let parsedObject: AnyObject? = NSJSONSerialization.JSONObjectWithData(data,
options: nil,
error:&err)
if let fullObject = parsedObject as? NSDictionary {
println("I am a dictionary")
} else {
println("O GOD WHY")
}
})
authSession.resume()
I'm afraid I can't show you the entirety of the data as that would provide insight into my companies authentication and user model. However, two things are worthy of note:
1) strData prints as Body:
Optional([{
2) The JSON structure is complex, containing multiple keys which map to integers, strings, objects ({}), arrays ([]) as well as arrays of objects and objects within objects.
response and data get printed out and are valid JSON, however data fails to cast to a dictionary. No error message is printed. How can I go about debugging this? Any ideas as to why this is happening?