PerformSegueWithIdentifier if parameter values are correct for http POST request - swift

When the parameter (params) values are incorrect, it still login to another view. In the console, both response body and response header return values when printed. Where have I gone wrong?
func login() {
let request = NSMutableURLRequest(URL: NSURL(string: "http://someurl/verify/")!)
let session = NSURLSession.sharedSession()
request.HTTPMethod = "POST"
let params =
[
"username":username.text!,
"password":password.text!,
"deviceid":"r49rvnjff",
"method":"method",
"payload":"payload"
]
as Dictionary<String,String>
print(params)
do {
request.HTTPBody = try NSJSONSerialization.dataWithJSONObject(params, options: .PrettyPrinted)
}
catch {
print(error)
return
}
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
let task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
if error == nil {}
let json: NSDictionary?
do {
json = try NSJSONSerialization.JSONObjectWithData(data!, options: .MutableLeaves) as? NSDictionary
}
catch let dataError {
print(dataError)
let jsonStr = NSString(data: data!, encoding: NSUTF8StringEncoding)
print("Error could not parse JSON: '\(jsonStr)'")
return
}
if let parseJSON = json {
let authenticated = parseJSON["authenticated"] as? String
print("authenticated:\(authenticated)")
if authenticated != "False" {
dispatch_async(dispatch_get_main_queue()) {
self.performSegueWithIdentifier("segue", sender: self)
}
}
}
else {
let jsonStr = NSString(data: data!, encoding: NSUTF8StringEncoding)
print("Error could not parse JSON: \(jsonStr)")
}
})
task.resume()
}
Thanks in advance!

What does your invalid response look like? might it be that its returning "false" and not "False" (which is what you are checking for), in any case I would recommend verifying your response from the server so that you can have the authenticated parameter be a boolean, so you can unwrap your optional as so:
if let authenticated = json["authenticated"] as? Bool {
if (authenticated)
{
// ...
}
}
Also, I noticed that your else block will never be hit because your json property is unwrapped. Your serialization is successful so json is not nil, hence the if let parseJSON = json will always work.
I would suggest the following approach:
if let authenticated = json["authenticated"] as? Bool
{
if (authenticated)
{
dispatch_async(dispatch_get_main_queue()) {
self.performSegueWithIdentifier("segue", sender: self)
}
}
else
{
let jsonStr = NSString(data: data!, encoding: NSUTF8StringEncoding)
print("Error could not parse JSON: \(jsonStr)")
}
}
Good luck!

Related

Swift: URLRequest uses body as JSON key

I'm using a generic function for POST requests in my app. I have the following function:
func PostRequest<In:Codable>(object: In, endpoint: String){
do{
let url = URL(string: "http://localhost:8080/\(endpoint)/")
var request = URLRequest(url: url!)
request.httpMethod = "POST"
request.httpBody = try JSONEncoder().encode(object)
URLSession.shared.dataTask(with: request) {data, response, error in
guard let data = data, error == nil else{
print(error?.localizedDescription ?? "No Data")
return
}
let JSONResponse = try? JSONSerialization.jsonObject(with: data, options: [])
if let JSONResponse = JSONResponse as? [String: Any] {
print(JSONResponse)
}
}.resume()
}catch{
print(error)
}
}
And in this case, the object is the following struct:
struct MarkAsDelivered: Codable{
let whoCollected: String
let deliveryID: Int
}
When I print the result of JSONEncoder().encode(object) as a string, it returns the following, as would be expected:
{
"whoCollected":"TESTNAME",
"deliveryID":140
}
however, when i view this JSON object on my backend, it returns it as the following:
{
"{\"whoCollected\":\"TESTNAME\",\"deliveryID\":140}" : ""
}
From what I can tell, it is using the JSON object as a key.
Does anyone know what has caused this issue. Any assistance would be greatly appreciated.
as #burnsi mentioned in the comments to my question, I was indeed missing the content type. Specifying it fixed my issue:
func PostRequest<In:Codable>(object: In, endpoint: String){
do{
let url = URL(string: "http://localhost:8080/\(endpoint)/")
var request = URLRequest(url: url!)
request.httpMethod = "POST"
//Added content type on line below:
request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
request.httpBody = try JSONEncoder().encode(object)
URLSession.shared.dataTask(with: request) {data, response, error in
guard let data = data, error == nil else{
print(error?.localizedDescription ?? "No Data")
return
}
let JSONResponse = try? JSONSerialization.jsonObject(with: data, options: [])
if let JSONResponse = JSONResponse as? [String: Any] {
print(JSONResponse)
}
}.resume()
}catch{
print(error)
}
}

urlrequest not sending post request

Hi i am new to IOS App developement.
My code is
func sendRequest<T: Decodable>(api: String, parameters: [String: String]? = nil, outputBlock: #escaping (T) -> () ) {
guard let url = URL(string: "http://xxyyzz.com/appRegister.php") else {return}
print("hitting : -", url.absoluteString)
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
let newparam = ["name": "rr", "pass": "123456", "email": "rr#rr.com", "passConfirm":"123456"]
let httpBody = try? JSONSerialization.data(withJSONObject: newparam)
request.httpBody = httpBody
if let data = request.httpBody, let str = String(data: data, encoding: String.Encoding.utf8) {
print(str)
}
URLSession.shared.dataTask(with: request as URLRequest) { (data, response, error) in
DispatchQueue.main.async {
Indicator.shared.hideProgressView()
if let err = error {
print(err.localizedDescription)
return
}
guard let data = data else {return}
do {
let obj = String(data: data, encoding: String.Encoding.utf8)
print(obj ?? "oberrrrr")
}
}
}.resume()
}
and console printed result as per code is below
hitting : - http://xxyyzz.com/appRegister.php
{"email":"rr#rr.com","passConfirm":"123456","name":"rr","pass":"123456"}
{"error":"Please enter all fields."}
url and parameters works well on postman that means their is something missing in my code.
just to answer the problem if anyone else faces this.
this code is fine but the problem was with php web-service as the backend developer was not accepting json values as parameter instead form data was need to send.
So, two types of fix can be made here
accept json at backend by adding :-
$postdata = file_get_contents("php://input");
$request = json_decode($postdata, true);
send form data instead json
func sendRequest<T: Decodable>(api: String, parameters: [String: Any]? = nil, outputBlock: #escaping (T) -> () ) {
guard let url = URL(string: api) else {return}
print("hitting : -", url.absoluteString)
var request = URLRequest(url: url)
if let parameters = parameters {
request.httpMethod = "POST"
var postArr = [String]()
for(key, value) in parameters
{
postArr.append(key + "=\(value)")
}
let postString = postArr.map { String($0) }.joined(separator: "&")
request.httpBody = postString.data(using: .utf8)
if let data = request.httpBody, let str = String(data: data, encoding: String.Encoding.utf8) {
print(str)
}
}
URLSession.shared.dataTask(with: request) { (data, response, error) in
DispatchQueue.main.async {
Indicator.shared.hideProgressView()
if let err = error {
print(err.localizedDescription)
return
}
guard let data = data else {return}
do {
let obj = try JSONDecoder().decode(T.self, from: data)
outputBlock(obj)
} catch let jsonErr {
print(jsonErr)
}
}
}.resume()
}

Send dictionary data via HTTP POST method in Swift

I'm trying to make an HTTP post request with params set in a dictionary here's my dict
let parameters = [
["name": "tag","value": "login"],
["name": "email","value": "s#s.com"],
["name": "password","value": "aaaa"]
]
but I don't to know how to access it in hers's my complete request function
func data_request(_ url:String)
{
let parameter = [
["name": "tag","value": "login"],
["name": "email","value": "s#s.com"],
["name": "password","value": "aaaa"]
]
let url:NSURL = NSURL(string: url)!
let session = URLSession.shared
let request = NSMutableURLRequest(url: url as URL)
request.httpMethod = "POST"
let paramString = parameter?
request.httpBody = paramString.data(using: String.Encoding.utf8)
let task = session.dataTask(with: request as URLRequest) {
(
data, response, error) in
guard let _:NSData = data as NSData?, let _:URLResponse = response, error == nil else {
print("error")
return
}
if let dataString = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
{
print(dataString)
}
}
task.resume()
}
Need to convert dictionary to json string like below:
let jsonData = try JSONSerialization.data(withJSONObject: parameters, options: .prettyPrinted)
After that pass to the http.Body
// insert json data to the request
request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
request.HTTPBody = jsonData
let task = NSURLSession.sharedSession().dataTaskWithRequest(request){ data, response, error in
if error != nil{
print("Error -> \(error)")
return
}
do {
let result = try NSJSONSerialization.JSONObjectWithData(data!, options: []) as? [String:AnyObject]
print("Result -> \(result)")
} catch {
print("Error -> \(error)")
}
}
task.resume()
return task
} catch {
print(error)
}
You need to convert the Dictionary into Data and set it to httpBody
you could solve in this way
let paramData = try? JSONSerialization.data(withJSONObject: parameter, options: [])
request.httpBody = paramData

How to wait for a download task to finish in swift 3

I am trying to build a user regeistration form, which should check if the user already exists. So I am sending a php request to my my mysql server. If the return value is empty, the user does not exists yet.
Unfortunatley I am really stuck with waiting for this check to finish. I tried several solutions I found googleing but none of them worked. My current code uses semaphores and will crash with "fatal error: unexpectedly found nil while unwrapping an Optional value", so the semaphore is not waiting until the task is finished as I would expect it.
Any hints, would be greatly appreciated. Thanks guys.
private func isUniqueEmail(email: String) -> Bool {
var result: Bool?
let semaphore = DispatchSemaphore(value: 1)
let requestURL = URL(string: "http://localhost/firstpostget/functions/get.php")
var request = URLRequest(url: requestURL!)
request.httpMethod = "POST"
let postParameters = "email=" + email
request.httpBody = postParameters.data(using: .utf8)
let configuration = URLSessionConfiguration.default
let session = URLSession(configuration: configuration, delegate: nil, delegateQueue: OperationQueue.main)
let task = session.dataTask(with: request) {(data, response, error) in
var myJson: AnyObject
do{
myJson = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) as AnyObject
if myJson.count == 0{
result = true
semaphore.signal()
} else{
result = false
semaphore.signal()
}
} catch{
//TODO
print(error)
}
}
task.resume()
semaphore.wait(timeout: .distantFuture)
return result!
}
Your task is async and you are force unwrapping nil value so this is the reason it crashes.
You have to change your function implementation to also be async, for example using closures:
private func isUniqueEmail(email: String, completion: ((Bool) -> (Void))?) {
let requestURL = URL(string: "http://localhost/firstpostget/functions/get.php")
var request = URLRequest(url: requestURL!)
request.httpMethod = "POST"
let postParameters = "email=" + email
request.httpBody = postParameters.data(using: .utf8)
let configuration = URLSessionConfiguration.default
let session = URLSession(configuration: configuration, delegate: nil, delegateQueue: OperationQueue.main)
let task = session.dataTask(with: request) {(data, response, error) in
var myJson: AnyObject
do{
myJson = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) as AnyObject
if myJson.count == 0 {
completion?(true)
} else{
completion?(false)
}
} catch{
//TODO
print(error)
}
}
task.resume()
}
Now you can use this function in this way:
isUniqueEmail(email: "aaa#bbbb.com") { result in
if result {
print("email unique")
} else {
print("email not unique")
}
}
I think you should rethink the pattern you're using to get the data out of your request, you should consider using a custom handler/callback method that you pass along with the email you're trying to check. See below for an example:
private func isUniqueEmail(email: String, handler: ((_ result: Bool) -> Void)?) -> Void {
let requestURL = URL(string: "http://localhost/firstpostget/functions/get.php")
var request = URLRequest(url: requestURL!)
request.httpMethod = "POST"
let postParameters = "email=" + email
request.httpBody = postParameters.data(using: .utf8)
let configuration = URLSessionConfiguration.default
let session = URLSession(configuration: configuration, delegate: nil, delegateQueue: OperationQueue.main)
let task = session.dataTask(with: request) {(data, response, error) in
var myJson: AnyObject
var result: Bool = false
do{
myJson = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) as AnyObject
if myJson.count == 0 {
result = true
}
guard handler != nil else {
return
}
handler!(result)
} catch{
//TODO
print(error)
}
}
task.resume()
}
Run:
isUniqueEmail(email: "test#test.com", handler: { result in
print(result) // true || false
})
If you really want to go down the "wait" route then take a took at DispatchGroup's
https://developer.apple.com/documentation/dispatch/dispatchgroup
try using this:
ApihelperClass
static let sharedInstance = ApihelperClass()
typealias CompletionHandler = (_ success:Bool, _ error:Bool, _ result:NSDictionary) -> Void
typealias ErrorHandler = (_ success: Bool, _ error:Bool) -> Void
func callPostRequest(_ urlPath: String, params:[String: AnyObject], completionHandler: #escaping CompletionHandler, errorHandler:#escaping ErrorHandler ){
print("urlPath:==> \(urlPath) ")
let session = Foundation.URLSession.shared
let url = URL(string: urlPath)
var request = URLRequest(url : url!)
request.httpMethod = "POST"
do {
let jsonData = try JSONSerialization.data(withJSONObject: params, options: .prettyPrinted)
request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
request.httpBody = jsonData
session.dataTask(with: request, completionHandler: { data, response, error in
OperationQueue.main.addOperation {
guard error == nil && data != nil else { // check for fundamental networking error
print("error=\(error)")
errorHandler(false, true)
return
}
if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 { // check for http errors
print("statusCode should be 200, but is \(httpStatus.statusCode)")
// print("response = \(response)")
}
let responseString = String(data: data!, encoding: String.Encoding.utf8)
print("responseString = \(responseString!)")
if let responsedata = responseString!.data(using: String.Encoding.utf8)! as? Data{
do {
let jsonResult:NSDictionary = try JSONSerialization.jsonObject(with: responsedata, options: []) as! NSDictionary
print("Get The Result \(jsonResult)")
//parse your jsonResult as per your requirements
if error != nil {
print("error=\(error)")
completionHandler(false, true, jsonResult)//
}
if let str = jsonResult["success"] as? NSNull {
print("error=\(str)")
completionHandler(false, true, jsonResult)
}
else {
let responseString = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
// print("Response string : \(responseString)")
completionHandler(true, false, jsonResult)
}
} catch let error as NSError {
print(error.localizedDescription)
}
}
}
}) .resume()
}catch {
print("Error ->Catch")
}
}
Add to your viewcontroller
func isUniqueEmail(email: String){
ApihelperClass.sharedInstance.callPostRequest("http://localhost/firstpostget/functions/get.php", params: ["email":email as AnyObject], completionHandler: { (success, error, result) in
//success 200
}) { (success, error) in
//error
}
}
you can use URlSession like :
func isUniqueEmail(email: String,completion: #escaping (Bool) -> ()) {
var request = URLRequest(url: URL(string: "http://localhost/firstpostget/functions/get.php")!)
request.httpMethod = "POST"
let postString = "email=\(email)"
request.httpBody = postString.data(using: .utf8)
// loading to wait request
UIApplication.shared.isNetworkActivityIndicatorVisible = true
let task = URLSession.shared.dataTask(with: request) { data, response, error in
// we get request request
UIApplication.shared.isNetworkActivityIndicatorVisible = false
guard let data = data, error == nil else { // check for fundamental networking error
print("error=\(String(describing: error))")
completion(false)
return
}
if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 { // check for http errors
print("statusCode should be 200, but is \(httpStatus.statusCode)")
print("response = \(String(describing: response))")
completion(false)
}else{
completion(true)
}
let responseString = String(data: data, encoding: .utf8)
print("responseString = \(String(describing: responseString))")
}
task.resume()
}
and used in code Like
self.isUniqueEmail(email: "your Email") { (isExit) in
if isExit {
}else{
}
}
Ok, I just found a solution. My semaphore approach actually worked as well as dispatchgroups. The task just needed to be URLSession.shared.dataTask
Still thank's a lot for all the answers.

swift http request crash nil value

I am using the following code to retrieve a response from a php page. Its works fine except every once in a while it crashes with an error after recieveing a nil value on the following line:
let responseString = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
is there a way I can catch this?
let myUrl = NSURL(string: "https://*****backend/newmessage.php")
let request = NSMutableURLRequest(url: myUrl! as URL)
request.httpMethod = "POST"
let postString = "userid=\(userid!)"
print(postString)
request.httpBody = postString.data(using: String.Encoding.utf8)
let task = URLSession.shared.dataTask(with: request as URLRequest) {
data, response, error in
DispatchQueue.global(qos: DispatchQoS.QoSClass.default).async {
let responseString = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
if error != nil {
print("Error: \(error)")
}
DispatchQueue.main.async() {
print(responseString!)
if (responseString! == "NEW"){
self.messageIcon.setImage(UIImage(named: "newmessage.png"), for: UIControlState.normal)
}else{
self.messageIcon.setImage(UIImage(named: "envelope.png"), for: UIControlState.normal)
}
}
}
}
task.resume()
Why not address a potential nil w/ an if-else statement? Alternatively, you could use a guard statement.
if responseString != nil { // do stuff } else { // do other stuff}