Parameters are not passed on Http post request? - ios

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.

Related

NSURLSession POST Request API

I am trying to upload the image as multipart form-data, but i am getting the error that status code 404 from server. Can anyone point out the mistake i am doing in this?
Server accepts "file" as key of the image that we are uploading.
This is what i am tried so far...
public func UPLOADING(url: String,parameters: Dictionary<String,AnyObject>?,filename:String,image:UIImage, success:((NSDictionary) -> Void)!, failed:((NSDictionary) -> Void)!, errord:((NSError) -> Void)!) {
let TWITTERFON_FORM_BOUNDARY:String = "AaB03x"
let url = NSURL(string: url)!
let request:NSMutableURLRequest = NSMutableURLRequest(url: url as URL, cachePolicy: NSURLRequest.CachePolicy.reloadIgnoringCacheData, timeoutInterval: 10)
let MPboundary:String = "--\(TWITTERFON_FORM_BOUNDARY)"
let endMPboundary:String = "\(MPboundary)--"
//convert UIImage to NSData
let data:NSData = UIImagePNGRepresentation(image)! as NSData
let body:NSMutableString = NSMutableString();
// with other params
if parameters != nil {
for (key, value) in parameters! {
body.appendFormat("\(MPboundary)\r\n" as NSString)
body.appendFormat("Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n" as NSString)
body.appendFormat("\(value)\r\n" as NSString)
}
}
// set upload image, name is the key of image
body.appendFormat("%#\r\n",MPboundary)
body.appendFormat("Content-Disposition: form-data; file=\"\(filename)\"\"\r\n" as NSString)
body.appendFormat("Content-Type: image/png\r\n\r\n")
let end:String = "\r\n\(endMPboundary)"
let myRequestData:NSMutableData = NSMutableData();
myRequestData.append(body.data(using: String.Encoding.utf8.rawValue)!)
myRequestData.append(data as Data)
myRequestData.append(end.data(using: String.Encoding.utf8)!)
let content:String = "multipart/form-data; boundary=\(TWITTERFON_FORM_BOUNDARY)"
request.setValue(content, forHTTPHeaderField: "Content-Type")
request.setValue("\(myRequestData.length)", forHTTPHeaderField: "Content-Length")
request.httpBody = myRequestData as Data
request.httpMethod = "POST"
let task = URLSession.shared.dataTask(with: request as URLRequest, completionHandler: {
data, response, error in
if error != nil {
print(error!)
errord(error! as NSError)
return
}
print(response ?? "")
do {
let responseObject:[String:Any]? = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? [String:Any]
if let responseDictionary = responseObject as NSDictionary? {
success(responseDictionary)
} else {
}
} catch let error as NSError {
print(error.localizedDescription)
}
})
task.resume()
}
In viewDidload,
let image = UIImage(named: "ed1.png",
in: Bundle(for: type(of: self)),
compatibleWith: nil)
UPLOADING(url: "url-of-site", parameters: nil, filename: "ed1.png", image: image!, success: { (sucDict) in
print(sucDict)
}, failed: { (failedDict) in
print(failedDict)
}) { (error) in
print(error.description)
}
I see several issues, mostly minor:
Your Content-Disposition: line is missing the 'name=file;' bit. This is one major reason why it isn't working.
Your boundary is way too short (by at least twenty characters or so; the upper bound is 70 characters, and you should use a good percentage of them). A short boundary runs a real risk of appearing in the actual data you're trying to send.
You should really be using NSData for constructing the entire body, rather than using a mutable string up until the last part.
Ideally, as you do so, you should check whether the boundary appears in any of the values, and if so, generate a new boundary and start over, until you succeed.
The Content-Type field should really be present on for every part unless the value is guaranteed to be 7-bit ASCII, because the Content-Type provides the character encoding (UTF-8, in this case). Otherwise, weird things may happen.
You should probably have a trailing CRLF after the end boundary, just for readability when debugging, though that shouldn't cause a failure.
Finally, if you're uploading to a public service like Twitter, you may need to add some sort of API key, either in the URL or in a request header, and the API might issue an error if that key is missing.
But none of those reasonably explain a 404 error. That should only be issued if the path to the script itself is wrong. This might be caused by something subtle, such as iOS preferring to hit servers via their IPv6 address over IPv4, and the IPv6 side of your web server might be misconfigured. Or it might be the wrong URL. Either way, the only way to debug that is to dig into your server logs and see what file it was trying to read, then figure out why that file doesn't exist.

Getting JSON Response from API Swift

At an earlier point today, I was able to use this API and get a response in my iPhone app. The fact that I have been trying to debug this for so long is making be believe that I'm crazy! Attached is a screenshot of my console...
Here is my code pertaining to my API call. Using Apple's URLSession and following many stack overflow questions / Tutorials I can not get this thing to work.
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data else {
print("request failed \(error)")
return
}
do {
if let json = try JSONSerialization.jsonObject(with: data) as? [String: String], let result = json["result"] {
// Parse JSON
}
} catch let parseError {
print("parsing error: \(parseError)")
let responseString = String(data: data, encoding: .utf8)
print("raw response: \(responseString)")
}
}
task.resume()
Every time I get this interesting [BoringSSL] Error and the searching I've done regarding that has not produced effective in fixing whatever bug I have.
Like I said, earlier today I had this app working using the same API. I have tried the key that the website gave me and the test key they use on their site. Now that I think of it, I am going to use the exact URL from my code and the screenshot and take a screenshot from the response I get in my browser. See below:
Received above response with the exact URL being used in my app.
tried your API in my project. It worked. You can check the difference below:
let urlTest = URL(string: "https://www.zipcodeapi.com/rest/wvyR5aWjHNUF80Z6kmr1bTuNojfzhmvtcmfBD8QNo9qbNAHy9FvBISINKF3W5i9J/multi-distance.json/99501/99501,%2085001,%2072201/km")
var request = URLRequest(url: urlTest!)
request.httpMethod = "GET"
let session = URLSession(configuration: .default)
let task : URLSessionDataTask = session.dataTask(with: request) { (data, response, error) in
let statusCode = (response as! HTTPURLResponse).statusCode
if statusCode == 200{
do {
let json = try JSON(data:data!)
}
catch {
print("Could not convert JSON data into a dictionary.")
}
}
}
task.resume()
Printing description of json:
▿ {
"distances" : {
"85001" : 4093.922,
"72201" : 4962.6189999999997
}
}
May be you have to turn off Transport Layer Security, because that worked for me.
Go to your info.plist file and add a property named App Transport Secrity Settings and set its Allow Arbitrary loads option to NO
Hope this helps.

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

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.

Data in HTTPBody with a PUT method fails, while it works with a POST?

first of all i would like to say i got the exact same problem as the following question: How to add data to HTTPBody with PUT method in NSURLSession?. But it wasn't answered so i made my own question.
We have written a node API for a school assignment. We've tested the whole API. (The chances of being something wrong there are slim.)
After that i went working on a iOS client to CRUD users.
Making a user is going perfectly, but whenever i try to edit a user something strange happens. The data on the server arrives as undefined.
I use the following code to save a user:
func saveUser(user: User, completionHandler: (String?, User?) -> Void) {
let url = NSURL(string: "https://pokeapi9001.herokuapp.com/api/users/")
let request = NSMutableURLRequest(URL:url!)
request.HTTPMethod = "POST"
let postString = "email=\(user.email)&password=\(user.password!)&role=\(user.role)"
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
request.cachePolicy = NSURLRequestCachePolicy.ReloadIgnoringCacheData
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
if error != nil {
print("error: \(error)")
}
do {
guard let data = data else {
throw JSONError.NoData
}
guard let json = try NSJSONSerialization.JSONObjectWithData(data, options: []) as? NSDictionary else {
throw JSONError.ConversionFailed
}
//do specific things
} catch let error as JSONError {
completionHandler(error.rawValue, nil)
} catch let error as NSError {
completionHandler(error.debugDescription, nil)
}
}
task.resume()
}
keep in mind, this is working perfectly (don't know if it is intended to be used like this)
To edit a user i use the following code:
func editUser(user: User, completionHandler: (String?, User?) -> Void) {
let url = NSURL(string: "https://pokeapi9001.herokuapp.com/api/users/\(user.id!)")
let request = NSMutableURLRequest(URL:url!)
request.HTTPMethod = "PUT"
let postString = "email=\(user.email)&password=\(user.password!)&role=\(user.role)"
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
request.cachePolicy = NSURLRequestCachePolicy.ReloadIgnoringCacheData
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
if error != nil {
print("error: \(error)")
}
do {
guard let data = data else {
throw JSONError.NoData
}
guard let json = try NSJSONSerialization.JSONObjectWithData(data, options: []) as? NSDictionary else {
throw JSONError.ConversionFailed
}
//do specific things
} catch let error as JSONError {
completionHandler(error.rawValue, nil)
} catch let error as NSError {
completionHandler(error.debugDescription, nil)
}
}
task.resume()
}
(The original code is a bit longer but i removed parts that had nothing to do with the actual posting of the data)
I have really no idea what i'm doing wrong, could be something small and stupid. Please help.
edit after input from #fiks
To be clear, the problem i am having is that I fill the "postString" the same way in the editUser method as I do in the saveUser method.(At least I think I do)
However in the saveUser method the postString seems to be correctly passed through to the API (it creates a new user with the given values).
The editUser method does not pass the values through.
If I put a console log on the server it shows all values are "undefined".
To test if the postString was correct on the iOS part I printed both strings out. Both of them outputted email=user#test.com&password=test&role=admin
From what I see in the postman request, you are sending a x-www-form-urlencoded request.
You have to specify it in the code. See example: POST request using application/x-www-form-urlencoded
Regarding Charles: since you are using https, you have to enable proxy for the host. More info here: https://www.charlesproxy.com/documentation/proxying/ssl-proxying/

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

Resources