Sending string from Node.js (Express) server to iOS Swift 3 - ios

I am trying to create a login system for my iOS mobile application. I have a request sending to my Node.js server with Swift 3 with:
#IBAction func loginBtn(_ sender: UIButton) {
//created NSURL
let requestURL = NSURL(string: loginURL)
//creating NSMutableURLRequest
let request = NSMutableURLRequest(url: requestURL! as URL)
//setting the method to post
request.httpMethod = "POST"
//getting values from text fields
let empNum = empTextField.text
let empPass = passTextField.text
//creating the post parameter by concatenating the keys and values from text field
let postParameters = "empNum=" + empNum! + "&empPass=" + empPass!;
//adding the parameters to request body
request.httpBody = postParameters.data(using: String.Encoding.utf8)
//creating a task to send the post request
let task = URLSession.shared.dataTask(with: request as URLRequest){
data, response, error in
if error != nil{
print("error is \(String(describing: error))")
return;
}
//parsing the response
do {
//converting resonse to NSDictionary
let myJSON = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary
print("myjson : \(String(describing: myJSON))")
//parsing the json
if let parseJSON = myJSON {
//creating a string
var msg : String!
//getting the json response
msg = parseJSON["message"] as! String?
//printing the response
print("message here: \(msg)")
}
} catch {
print("Error here: \(error)")
}
}
//executing the task
task.resume()
}
I am getting a 200 server side but I want to be able to res.send a string back to Swift so I can proceed to take further actions. How do I check that response? Like:
if response == "vaild" {
...
}else{
...
}
When I run this code I get an error that reads:
Error here: Error Domain=NSCocoaErrorDomain Code=3840 "JSON text did not start with array or object and option to allow fragments not set." UserInfo={NSDebugDescription=JSON text did not start with array or object and option to allow fragments not set.}
P.S. I am also not really familiar with the request code so if it is right in front of my face please just explain the code to me then. Sorry in advance!!

Your code sample suggests that your client expects a json response with a property message in it. If you are using resp.send('Success') from your server it will not be a json object. It will be a string.
If that is what you want on your server response you should update your client to simply parse the data to a string. You can use String(data: data, encoding: .utf8) where "data" is what is returned from the response.
However, I would recommend leveraging HTTP Status codes. In your server code you can respond with a 422 if login was not successful. This can be accomplished with resp.status(422).send('Some optional message'). Then client side all you need to do is check the response status. Instead of a string compare.

Related

Parameters are not passed on Http post request?

Hai I am trying to pass some parameters of string in Http post request. I have created a dictionary and then converted that dictionary to data and set as httpBody.But when I looked on our server nothing has been passd I mean parameters are empty.Why? What mistake i am doing?Please help me to find out.Thanks in advance.
func receiptValidation(productId:String,requestFrom:String)
{
let SUBSCRIPTION_SECRET = "mySecretKey"
let defaults = UserDefaults.standard
let receiptPath = Bundle.main.appStoreReceiptURL?.path
if FileManager.default.fileExists(atPath: receiptPath!){
var receiptData:NSData?
do {
receiptData = try NSData(contentsOf: Bundle.main.appStoreReceiptURL!, options: NSData.ReadingOptions.alwaysMapped)
}
catch{
print("ERROR: " + error.localizedDescription)
}
//let receiptString = receiptData?.base64EncodedString(options: NSData.Base64EncodingOptions(rawValue: 0))
let base64encodedReceipt = receiptData?.base64EncodedString(options: NSData.Base64EncodingOptions.endLineWithCarriageReturn)
print(base64encodedReceipt!)
let requestDictionary = ["receipt-data":base64encodedReceipt!,"password":SUBSCRIPTION_SECRET]
guard JSONSerialization.isValidJSONObject(requestDictionary) else { print("requestDictionary is not valid JSON"); return }
do {
let requestData = try JSONSerialization.data(withJSONObject: requestDictionary)
let requestDataString=String(describing: requestData)
let URLForApplication:String = String(format:"%#/api/validate-receipt-data",opcodeDetails["apiProxyBaseUrl"]!) // this works but as noted above it's best to use your own trusted server
SwiftyBeaver.info("URLForApplication Path:\n\(URLForApplication)")
let url:URL! = URL.init(string: URLForApplication)
var request = URLRequest.init(url: url)
request.httpMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
let configure = URLSessionConfiguration.background(withIdentifier: Bundle.main.bundleIdentifier!)
session1=URLSession(configuration: .default, delegate: applicationDelegate.application, delegateQueue: OperationQueue.main)
var postString =
["receiptData":requestDataString,
"deviceType":"IOS",
"subscriberId":encodeString(normalString: defaults.array(forKey: "userDetails")?.first as! String),
"password":encodeString(normalString: defaults.array(forKey: "userDetails")?.last as! String),
"productId":encodeString(normalString: productId ),
"code":opcodeDetails["opCode"]!]
do {
request.httpBody = try JSONSerialization.data(withJSONObject: postString, options: .prettyPrinted) // pass dictionary to nsdata object and set it as request body
} catch let error {
print(error.localizedDescription)
}
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
let task = session1?.dataTask(with: request) { (data, response, error) in
if let data = data , error == nil {
do {
let appReceiptJSON = try JSONSerialization.jsonObject(with: data)
print("success. here is the json representation of the app receipt: \(appReceiptJSON)")
// if you are using your server this will be a json representation of whatever your server provided
} catch let error as NSError {
print("json serialization failed with error: \(error)")
}
} else {
print("the upload task returned an error: \(error)")
}
}
task?.resume()
} catch let error as NSError {
print("json serialization failed with error: \(error)")
}
}
}
and what error i am getting is Error Domain=NSCocoaErrorDomain Code=3840 "JSON text did not start with array or object and option to allow fragments not set." UserInfo={NSDebugDescription=JSON text did not start with array or object and option to allow fragments not set.}
You don’t say, but I’m assuming you’re getting this error where you print “json serialization failed with error”. If so, CZ54 is right, that your response is obviously not JSON. So, where you print that error, also print the header and body to see what the server actually returned, if anything:
print("response header:", response ?? "No response")
print("response body:", String(data: data, using: .utf8) ?? "No body")
The response header will include the status code (which should be something in the 200...299 range). If it’s not in that range, the status code will tell you the broad nature of the problem.
And regarding the response body, Sometimes (esp in development environments) if the server choked on something, it may return a HTML page outlining the nature of the problem (though, admittedly, in other cases, it only outputs the fact that there was an error, but not the details, and you’ll need to go into the server error logs to figure out what went wrong).
Looking at the specifics of the response, like above, is is your first step. Or you can achieve this by running the app on a simulator, and watching the request and the response in a tool like Charles or Wireshark. Once you get them up and running, these are great tools for inspecting requests and responses.
The next question is why the server generated the response that it did. As a general rule, while these sorts of problems can be a result of some server mistake, the more likely scenario is that the request wasn’t formed correctly and the server didn’t know how to handle it. Looking at the response (or looking at your server’s error logs) often provides good clues. But there’s no way anyone can help you on the basis of the information provided.

Swift 3 - issue to create easy request method POST (URLRequestVonvertible)

I am developing an application with Swift 3.0 and IOS 10 in Xcode 8.3.2. But I have a problem when I try to retrieve the JSON from this APIRest (http://schematic-ipsum.herokuapp.com/). What is the problem? Or how you would make the call. If you need more information regarding the code, tell me, but basically, I just want to make a call to that page to recover the biography.
enter image description here
My code is this:
import AlamofireDomain
import Alamofire
import ObjectMapper
class AuthorDAO : SimpleDAO {
func getBiography(_ parameters: Dictionary<String, Int>,
callbackFuncionOK: #escaping
(PropertiesAuthorModel)->(),
callbackFunctionERROR: #escaping (Int,NSError)->()) {
let ulr = NSURL( string: "http://schematic-ipsum.herokuapp.com/" as String)
let request = NSMutableURLRequest(url: ulr! as URL)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Constent-Type")
let data = try! JSONSerialization.data(withJSONObject: parameters, options: JSONSerialization.WritingOptions.prettyPrinted)
let json = NSString(data: data, encoding: String.Encoding.utf8.rawValue)
if let json = json {
print(json)
}
request.httpBody = json!.data(using: String.Encoding.utf8.rawValue)
Alamofire.request(request as URLRequest)
.responseJSON { response in
if response.result.isSuccess{
if let status = response.response?.statusCode {
switch(status){
//MARK: CONTROL ON DIFERENTS KINDS OF RESPONSES ON SERVER
case 200:
if let value = response.result.value {
let biographyResponse = Mapper<PropertiesAuthorModel>().map(JSONObject: value)
callbackFuncionOK(biographyResponse!)
}
//case 400: {} ..., case 404: {} ...
default:
break
}
}
}
//MARK: ERROR ON SERVER
else {
var statusCode = -1
if let _response = response.response {
statusCode = _response.statusCode
}
var nsError: NSError = NSError(domain: Constants.UNKNOWN_HTTP_ERROR_MSG,
code: Constants.UNKNOWN_HTTP_ERROR_ID,
userInfo: nil)
if let _error = response.result.error {
nsError = _error as NSError
}
callbackFunctionERROR(statusCode,nsError)
}
}
}
And the error is: "Error Domain=Alamofire.AFError Code=4 "JSON could not be serialized because of error: The data couldn’t be read because it isn’t in the correct format." 400"
The problem is that it does not enter into the "if response.result.isSuccess {" because the result of the response is "nil" and goes directly to the "else". Showing the error that I have commented. Can it be because I have to send the JSON format in the httpBody request? How can I do it?
Your question should be more clear. "What is the problem?" isn't possible to answer without more information.
To issue HTTP request, take a look at Alamofire, an HTTP networking library written in Swift: https://github.com/Alamofire/Alamofire
Alamofire.request("https://httpbin.org/get").responseJSON { response in
print(response.request) // original URL request
print(response.response) // HTTP URL response
print(response.data) // server data
print(response.result) // result of response serialization
if let JSON = response.result.value {
print("JSON: \(JSON)")
}
}

Properly formatting JSON object in Swift 3

I'm having an issue getting my JSON object in a proper format on my server running Node.js. I have my API set up to receive a JSON object and store it in a database. This works great when I send it a POST request from postman (as shown below), but it throws an odd error when I send it from iOS. As an example:
The first json object shown is sent from postman. The second one is from iOS (using Swift 3). The error essentially crashes the server, saying:
AssertionError: Error: key {"firstname":"testFirstName","lastname":"testLastName","email":"testemail123#gmail.com","username":"testusername123", == null
I'm not exactly sure why this is the case. I assume it has to do with the way the object is created? This is the swift code I'm using to create the object:
let infoDictionary = [
"username": UserNameField.text!,
"password": PasswordField.text!,
"firstname": FirstNameField.text!,
"lastname": LastNameField.text!,
"email": EmailField.text!
]
// Whole block = send above dictionary as JSON to server:
if JSONSerialization.isValidJSONObject(infoDictionary) {
do {
let jsonObject = try JSONSerialization.data(withJSONObject: infoDictionary,
options: .prettyPrinted)
I then append that to the http body. Note that the fields are from text fields in the UI of the app that I unwrap and place into a dictionary. When I print it out as a string in swift, it comes out as the correct format, there is just something going wrong when I actually go to send it to my server.
EDIT: Per request the full URL request is below:
do {
let jsonObject = try JSONSerialization.data(withJSONObject: infoDictionary,
options: .prettyPrinted)
// Create Post request
let url = URL(string: "websiteurl")
var request = URLRequest(url: url!)
request.httpMethod = "POST"
// Append JSON object
request.httpBody = jsonObject
// Send request
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else {
print(error?.localizedDescription ?? "No Data")
return
}
let responseJSON = try? JSONSerialization.jsonObject(with: data, options: [])
if let responseJSON = responseJSON as? [String: Any] {
print(responseJSON)
}
}
task.resume() // Sends the request
} catch {
print(error.localizedDescription)
}
}
The request body is fine, it contains a valid JSON object, but
apparently the server interprets the HTTP body as string and wraps
it into another JSON object. Note that "text/plain" is the default
content type for HTTP requests (https://www.rfc-editor.org/rfc/rfc2045#section-5.2).
The solution is to set the content type explicitly:
request.addValue("application/json", forHTTPHeaderField: "Content-type")

How to get userID from JSON response while JSON text did not start with array or object and option to allow fragments not set

I got json response from server like this:
"{\"userID\":\"dkjagfhaghdalgalg\"}"
I try to get that userID with this:
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
(data, response, error) -> Void in
if let unwrappedData = data {
do {
let userIDDictionary:NSDictionary = try NSJSONSerialization.JSONObjectWithData(unwrappedData, options: NSJSONReadingOptions.MutableContainers) as! NSDictionary
print("userIDDictionary:\(userIDDictionary)")
//let userID:String = userIDDictionary["userID"] as! String
//print("userID:\(userID)")
print("data:\(data)")
print("response:\(response)")
print("error:\(error)")
} catch {
print("Failed to get userID: \(error)")
}
}
}
but the response is
Failed to get userID: Error Domain=NSCocoaErrorDomain Code=3840 "JSON text did not start with array or object and option to allow fragments not set. UserInfo={NSDebugDescription=JSON text did not start with array or object and option to allow fragments not set.}".
How to get userID with json response like that?
update: I try to get with anyobject but still did not get that json string to change to dictionary.
let bodyStr = "test={ \"email\" : \"\(username)\", \"password\" : \"\(password)\" }"
let myURL = NSURL(string: Constant.getSignInEmail())!
let request = NSMutableURLRequest(URL: myURL)
request.HTTPMethod = "POST"
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.setValue("application/json", forHTTPHeaderField: "Accept")
request.HTTPBody = bodyStr.dataUsingEncoding(NSUTF8StringEncoding)!
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
(data, response, error) -> Void in
if let unwrappedData = data {
do {
let json:AnyObject! = try NSJSONSerialization.JSONObjectWithData(unwrappedData, options: NSJSONReadingOptions.MutableContainers) as! AnyObject
print("json:\(json)")
//let userID:String = userIDDictionary["userID"] as! String
//print("userID:\(userID)")
} catch {
print("Failed to get userID: \(error)")
}
}
}
Try with try with NSJSONReadingOptions.AllowFragments in json reading options
I think this is a case of confusion between the data that you are receiving and the way they are displayed. Either on your side, or on the server side. Try to tell us exactly what the server is sending, byte for byte.
What you have got there is a string containing JSON. Not JSON, but a string containing JSON. Which is not the same. Just like a bottle of beer is not made of beer, but of glass.
If this is indeed what you are receiving, then you should first kick the guys writing the server code. If that doesn't help, then read what the "fragment" option does; this will give you a string, then you extract the bytes, and throw the bytes into a JSON parser.
Two way you can resolve.
Check your Webservice format and correct it as {"key":"value","key":"value"}
or else you have to Convert NSData to NSString.
Using String(data:, encoding:.utf8)
then format the string file with reduction '\'
then again convert it to NSData type then Call JSONSerialization.
Actually this is NSASCIIStringEncoding.
For help, I created a program.
Please just copy/paste and run it. You will find your answer.
import Foundation
let string = "{\"userID\":\"dkjagfhaghdalgalg\"}"
let unwrappedData: NSData = string.dataUsingEncoding(NSASCIIStringEncoding)!
do {
let userIDDictionary:NSDictionary = try NSJSONSerialization.JSONObjectWithData(unwrappedData, options: NSJSONReadingOptions.MutableContainers) as! NSDictionary
let userid = userIDDictionary.valueForKey("userID")
print("userid:\(userid!)")
} catch {
print("Failed to get userID: \(error)")
}

Getting error In posting Data in swift

I am sending the data using post method like this
let login = ["user_name":usernameTextField.text,"password":passwordTextField.text]
//["user":"ords_user#gmail.com", "pass":"ords_password"]
let url = NSURL(string: "http://localhost:8300")!
let session = NSURLSession.sharedSession()
let request = NSMutableURLRequest(URL: url)
do {
// JSON all the things
let auth = try NSJSONSerialization.dataWithJSONObject(login, options: .PrettyPrinted)
// Set the request content type to JSON
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
// The magic...set the HTTP request method to POST
request.HTTPMethod = "POST"
// Add the JSON serialized login data to the body
request.HTTPBody = auth
// Create the task that will send our login request (asynchronously)
let task = session.dataTaskWithRequest(request, completionHandler: { (data, response, error) -> Void in
// Do something with the HTTP response
print("Got response \(response) with error \(error)")
print("Done.")
})
// Start the task on a background thread
task.resume()
} catch {
// Handle your errors folks...
print("Error")
}
But I am getting the error message like
Argument type '[String : String?]' does not conform to expected type ‘AnyObject’
If I give the direct string it is accepting. If I am giving dynamically using the TextFields it is not coming. I don’t know what is the mistake I have done.
Can anyone Please help to solve this issue?
Thanks in advance.
I think your issue is that you are putting optional strings into the dictionary.
Try doing this:
guard
let username = usernameTextField.text,
let password = passwordTextField.text else {
return print("Need username & password")
}
let login = ["user_name": username,"password": password]
...
UITextField's text property returns an optional value, so compiler can't convert it to AnyObject.
You have to unwrap optionals before.
Try this
let login = ["user_name":usernameTextField.text,"password":passwordTextField.text] as Dictionary<String, AnyObject>

Resources