Swift : HTTP 500 Error when calling from callback - ios

Here is my code I am using( the login part executes successfully, "Logged in successfully" is readable in the console )
#IBAction func loginAction(_ sender: Any) {
print("loginIsExecuting")
Server.Login(email: inputEmail.text!, password: inputPassword.text!, handlerDone:{
print("Logged in successfully")
Help.getData();
}, handlerFailed: {
print("===Failed to log in ")
DispatchQueue.main.sync {
self.displayAlert()
}
})
}
Help.swift
import Foundation
class Help {
static func getData(){
let urlString = URL(string: "http://192.168.1.16/~peterlizak/Secway/web/app/get-auditor")
if let url = urlString {
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
if error != nil {
print(error)
} else {
let responseString = String(data: data!, encoding: .utf8)
print(responseString) //JSONSerialization
}
}
task.resume()
}
}
}
While executing I am getting a 500 Internal Server Error.
This is from the apache log :
192.168.1.16 - - [13/Oct/2017:12:04:30 +0200] "POST /~Myname/Myapp/web/app/get-auditor HTTP/1.1" 500 495
Using the same code only calling Help.getData() after Server.login (not in the callback function) is working when I execute the code only once. But if I click the button again to trigger loginAction() ,again the function behaves as it does in the first version: the login executes, "Logged in successfully" is in the console, but when the code tries to execute the HTTP request it gets the same HTTP 500 error.(Also that solution is not acceptable because I must call first login and after the data)
I am using symphony for the backend and this is my simple code I try to request :
/**
* #Route("/get-auditor" , name="get_auditor")
*/
public function getAuditorInfoAction(Request $request)
{
$data = array(
'status' => 1,
'description' => 1,
"header" => 1
);
return new JsonResponse($data);
}
EDIT:
Server.Login
static func Login(email: String , password: String ,handlerDone:#escaping () -> Void,handlerFailed:#escaping () -> Void) {
print("=== Server Login ===")
let url = URL(string: "\(self.baseUrl)~peterlizak/Secway/web/app/login")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
let parameters = ["email": email, "password": password]
do {
request.httpBody = try JSONSerialization.data(withJSONObject: parameters, options: .prettyPrinted)
} catch let error {
print(error.localizedDescription)
}
CallService(request: request, handlerDone:{ json in
ParseLoginResponse(json: json)
handlerDone()
}, handlerFailed: {
handlerFailed()
} )
}
Server.CallService
static func CallService(request:URLRequest,handlerDone: #escaping (_ json:[String:Any]) -> Void,handlerFailed: #escaping () -> Void)
{
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else { // check for fundamental networking error
print("error=\(String(describing: error))")
handlerFailed()
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)")
handlerFailed()
return
}
let responseString = String(data: data, encoding: .utf8)
var json:[String:Any]
do {
json = (try JSONSerialization.jsonObject(with: data, options: [])) as! [String:Any]
}
catch {
print("json error calling "+(request.url?.absoluteString)!+" =\(String(describing: error))")
print("responseString = \(responseString!)")
handlerFailed()
return
}
let status = json["status"] as! Int
if status != 0{
handlerDone(json)
}
else{
print("status is 0 = \(responseString!)")
handlerFailed()
}
}
task.resume()
}

HTTP 500 is an internal server error and not a client error. There will be some exception in related method in server for this API call. This error usually means something goes wrong in the server and need to look into the error trace.

You are mostly likely sending request to the wrong url since in the code you have /~peterlizak/Secway and error response has /~Myname/Myapp

Related

How to get JSON response data from shared class to ViewController?

I'm not using Alamofire, so i want to use JSON post approach in SharedClass and i want to send my api name and all parameters to that function. Finally i want to get the response back. I tried but it's not working. If it's not correct please correct me or if any other options are available please suggest me.
My code in SharedClass
func postRequestFunction(apiName:String , parameters:String ) -> [String:Any] {
var localURL = "hostname/public/index.php/v/***?"
localURL = localURL.replacingOccurrences(of: "***", with: apiName)
var request = URLRequest(url: URL(string: localURL)!)
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.httpMethod = "POST"
print("shared URL : \(request)")
request.httpBody = parameters.data(using: .utf8)
var returnRes:[String:Any] = [:]
let task = URLSession.shared.dataTask(with: request) { data, response, error in guard let data = data, error == nil else { // check for fundamental networking error
print(error!)
// print("error=\(String(describing: error))")
print("localizedDescription : \(String(describing: error?.localizedDescription))")
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))")
}
do {
returnRes = try JSONSerialization.jsonObject(with: data, options: []) as! [String : Any]
print(returnRes)
} catch let error as NSError {
print(error)
}
}
task.resume()
return returnRes
}
In my view controller class my code is. Here i'm calling function
func getProjectDetails() {
let response = SharedClass.sharedInstance.postRequestFunction(apiName: "API Name", parameters: parameters)
print(response)
let res = response["Response"] as! [String:Any]
let status = res["status"] as! String
if status == "SUCCESS" {
//I will handle response here
} else {
let message = res["message"] as! String
//Call alert function
SharedClass.sharedInstance.alert(view: self, title: "", message: message)
}
}
Here is my solution:
class APIManager {
private init () {}
static let shared = APIManager()
func postRequestFunction(apiName: String , parameters: String, onCompletion: #escaping (_ success: Bool, _ error: Error?, _ result: [String: Any]?)->()) {
var localURL = "hostname/public/index.php/v/***?"
localURL = localURL.replacingOccurrences(of: "***", with: apiName)
var request = URLRequest(url: URL(string: localURL)!)
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.httpMethod = "POST"
print("shared URL : \(request)")
request.httpBody = parameters.data(using: .utf8)
var returnRes:[String:Any] = [:]
let task = URLSession.shared.dataTask(with: request) { data, response, error in
if let error = error {
onCompletion(false, error, nil)
} else {
guard let data = data else {
onCompletion(false, error, nil)
return
}
if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode == 200 {
do {
returnRes = try JSONSerialization.jsonObject(with: data, options: []) as! [String : Any]
onCompletion(true, nil, returnRes)
} catch let error as NSError {
onCompletion(false, error, nil)
}
} else {
onCompletion(false, error, nil)
}
}
}
task.resume()
}
}
func getProjectDetails() {
/* Notes:
** onCompletion Block Parameters:
success - This indicates whether the API called successfully or not.
error - This indicates errors from either API calling failed, JSON parsing, or httpStatus is not 200.
result - This indicates the JSON parsed result.
** APIManager:
I have renamed your SharedClass to APIManager for better readibility.
** sharedInstance:
I have renamed sharedInstance to shared for better readibility.
*/
APIManager.shared.postRequestFunction(apiName: "API Name", parameters: "parameters") { (success, error, result) in
if success {
if let res = result?["Response"] as? [String: Any] {
if let status = res["status"] as? String {
if status == "SUCCESS" {
//You can handle response here.
} else {
let message = res["message"] as! String
//Call alert function.
}
}
}
} else {
print(error?.localizedDescription)
}
}
}
You forgot the asynchronous paradigm of Service, You can return your API response in Closure, as like below
func postRequestFunction(apiName:String , parameters:String, returnRes: #escaping ([String: Any]) -> () ) {
var localURL = "hostname/public/index.php/v/***?"
localURL = localURL.replacingOccurrences(of: "***", with: apiName)
var request = URLRequest(url: URL(string: localURL)!)
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.httpMethod = "POST"
print("shared URL : \(request)")
request.httpBody = parameters.data(using: .utf8)
let task = URLSession.shared.dataTask(with: request) { data, response, error in guard let data = data, error == nil else {
// check for fundamental networking error
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))")
}
do {
if let response = try JSONSerialization.jsonObject(with: data, options: []) as? [String : Any] {
returnRes(response)
}
} catch let error as NSError {
print(error)
}
}
task.resume()
}
And use like below
postRequestFunction(apiName: "yourUrl", parameters: "Param") { (response) in
print(response)
}

How parse JSON from 2 URLs properly?

I need to parse JSON from 2 different URL's
let jsonUrlStr1 = "https://123"
let jsonUrlStr2 = "https://325"
guard let url1 = URL(string: jsonUrlStr1) else { return }
guard let url2 = URL(string: jsonUrlStr2) else { return }
Here I'm running session for 1st url:
URLSession.shared.dataTask(with: url1) { (data, response, err) in
if err != nil {
print("Error:\(String(describing: err))")
}
guard let data = data else { return }
do {
let myData1 = try JSONDecoder().decode(SomeJsonModel1.self, from: data)
//Some code
} catch let jsonErr {
print("Error:\(jsonErr)")
}
}.resume()//URLSession
And then again, I'm running another session for 2nd url, using the same way:
URLSession.shared.dataTask(with: url2) { (data, response, err) in
if err != nil {
print("Error:\(String(describing: err))")
}
guard let data = data else { return }
do {
let myData2 = try JSONDecoder().decode(SomeJsonModel2.self, from: data)
//Some code
} catch let jsonErr {
print("Error:\(jsonErr)")
}
}.resume()//URLSession
This code works and I get the result.
But I think there should be a more correct way to parse 2 URLs.
Please advise how to do it correctly. Thanks.
You can try using completion block like this :
func getDataFromJson(url: String, completion: #escaping (_ success: [String : Any]) -> Void) {
let request = URLRequest(url: URL(string: url)!)
let task = URLSession.shared.dataTask(with: request) { Data, response, error in
guard let data = Data, error == nil else { // check for fundamental networking error
print("error=\(String(describing: error))")
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!)
return
}
let responseJSON = try! JSONSerialization.jsonObject(with: data, options: .allowFragments) as! [String : Any]
completion(responseJSON)
}
task.resume()
}
and call method like this :
let jsonUrlStr1 = "https://123"
let jsonUrlStr2 = "https://325"
getDataFromJson(url: jsonUrlStr1, completion: { response in
print("JSON response for url1 :: ",response) // once jsonUrlStr1 get it's response call next API
getDataFromJson(url: jsonUrlStr2, completion: { response in
print("JSON response for url2 :: ",response)
})
})

JSON conversion is getting failed

Please review my code am badly stuck on this issue.
JSON conversion is not happening & it is going into catch block & printing following error.
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.}
I've tried everything which is suggested here on StackOverflow but no luck.
I've trimmed my code for better understanding.
import Foundation
class Server
{
class func convertStringToDictionary(_ data: Data) -> [String:Any]?
{
do
{
let convertedDict = try JSONSerialization.jsonObject(with: data, options: []) as? [String:Any]
return convertedDict
}
catch let error as NSError
{
print(error)
}
return nil
}
class func registerUser( userInfo: String)
{
let url = URL(string: "http://132.148.18.11/missedprayers/welcome/register")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
let postString = "request=" + userInfo
request.httpBody = postString.data(using: .utf8)
//----------------------------------------
let task = URLSession.shared.dataTask(with: request)
{
data, response, error in
guard let data = data, error == nil
else
{
print("error=\(error)")
return
}
if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200
{
print("statusCode should be 200, but is \(httpStatus.statusCode)")
print("response = \(response)")
}
//--------------
let finalData = Server.convertStringToDictionary(data)
print(finalData)
}
task.resume()
}
func submitBtnTapped(_ sender: AnyObject)
{
let userInfoDict = [
"name":"Maaz Patel",
"phoneNum":"+91899885623",
"email":"maaz#gmail.com",
"city":"pune",
"country":"India",
"dobEnglish":"11-02-1992",
"app":"Dalail",
"aqeeda":"Sufi",
"gender":"male",
"MCCycle":""
]
//-------------------
do
{
let jsonData = try JSONSerialization.data(withJSONObject: userInfoDict, options: [] )
let jsonStr = String.init(data: jsonData, encoding: String.Encoding.utf8)
Server.registerUser(userInfo: jsonStr!)
}
catch let error as NSError
{
print(error)
}
}
}
Consider "SubmitBtnTapped" function is getting called from somewhere.
When am trying on Postman it's working also on Android same web service is working fine.

Save and send cookie after HTTP request

I'm login through an API using a POST request with URLRequest and URLSession. Everything seems to work well since I receive the correct response from the API.
Then I want to send a GET request to the same API but it seems that I'm not connected anymore.
For what I saw, the API is sending a Cookie in its Header in that form :
Cookie:PHPSESSID=abc123
I guess the problem is coming from that cookie wich is not send when I do a GET Request.
Here is my code.
ViewController :
#IBAction func Connection(_ sender: AnyObject) {
let loginFunc = Login()
loginFunc.login(username: username.text!, password: password.text!) { jsonString in
let response = jsonString
print(response)
}
let get = GetRequest()
get.get(req: "patient/info") { jsonString in
let response = jsonString
print(response)
}
}
Login.swift :
class Login {
func login(username: String, password: String, completion: #escaping (String) -> ()) {
var request = URLRequest(url: URL(string: "http://myurl/web/app_dev.php/login_check")!)
request.httpMethod = "POST"
let config = URLSessionConfiguration.default
let postString = "_username=" + username + "&_password=" + password
request.httpBody = postString.data(using: .utf8)
var responseString = ""
let mysession = URLSession.init(configuration: config)
let task = mysession.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else { // check for fundamental networking error
print("error=\(error)")
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)")
}
responseString = String(data: data, encoding: .utf8)!
let httpResponse = response as! HTTPURLResponse
let field = httpResponse.allHeaderFields["Cookie"]
print(field)
print(type(of: response))
completion(responseString)
}
task.resume()
}
}
GetRequest.swift :
class GetRequest {
func get(req: String, completion: #escaping (String) -> ()) {
var request = URLRequest(url: URL(string: "http://myurl/web/app_dev.php/" + req)!)
request.httpMethod = "GET"
var responseString = ""
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else { // check for fundamental networking error
print("error=\(error)")
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)")
}
responseString = String(data: data, encoding: .utf8)!
print(responseString)
completion(responseString)
}
task.resume()
}
}
Hey for sending cookies along with your ajax request please use. You need to use withCredentials to true.
$.ajaxSetup({
dataType: 'json',
contentType: 'application/json',
async: true,
cache: false,
processData: false,
crossDomain: true,
xhrFields: {
withCredentials: true
}
});

how i can make a HTTP request with Swift 3?

Im learning about Swift and i trying to make an HTTP request. My code is working but i dont know how to return the result of the request:
func makeRequest(request: URLRequest)->String{
let task = URLSession.shared.dataTask(with: request){data, response, error in
guard let data = data, error == nil else{
print("error=\(error)")
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)")
}
print (data)
do {
let json = try JSONSerialization.jsonObject(with: data, options: .allowFragments)
print(json)
} catch {
print("error serializing JSON: \(error)")
}
//print("responseString = \(responseString)")
}
task.resume()
return "Something"//i need to return the json as String
}
Someone can help me please? i was trying using CompletionHanlder but all the example that i found is based on swift 2, and this causes error on my code
The completion handler's type needs to be something like this:
#escaping ({argument types...})->{result type}
#escaping is needed as the completion handler is executed later when the communication is completed.
{argument types...} needs to be the types you want to pass to the handler, so in your case, a single type String. And you usually do not use the result from the handler, so you need to specify Void (aka ()).
Thus your completion handler's type needs to be:
#escaping (String)->Void
So, your method header becomes:
(You know you need a closing parenthesis for argument list.)
func makeRequest(request: URLRequest, completion: #escaping (String)->Void)
Whole your method would be something like this:
func makeRequest(request: URLRequest, completion: #escaping (String)->Void) {
let task = URLSession.shared.dataTask(with: request) {data, response, error in
guard let data = data, error == nil else{
print("error=\(error)")
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)")
}
print(data as NSData) //<-`as NSData` is useful for debugging
do {
let json = try JSONSerialization.jsonObject(with: data, options: .allowFragments)
print(json)
//Why don't you use decoded JSON object? (`json` may not be a `String`)
} catch {
print("error serializing JSON: \(error)")
}
//Not sure what you mean with "i need to return the json as String"
let responseString = String(data: data, encoding: .utf8) ?? ""
completion(responseString)
}
task.resume()
}
You can use it as:
makeRequest(request: request) {response in //<-`response` is inferred as `String`, with the code above.
print(response)
}
func makeRequest(request: URLRequest, completion: (result : String?)->() {
let task = URLSession.shared.dataTask(with: request){data, response, error in
guard let data = data, error == nil else{
print("error=\(error)")
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)")
}
print (data)
do {
let json = try JSONSerialization.jsonObject(with: data, options: .allowFragments)
print(json)
} catch {
print("error serializing JSON: \(error)")
}
completion("yourResultString")
//print("responseString = \(responseString)")
}
task.resume()
}
to call it
makeRequest(request: request) { (result : String?) in
if let result = result {
print("got result: \(result)")
}
You can't "return" the result of the request. By the time you have a result your makeRequest function has already returned to its caller. You should:
Change makeRequest to not return anything, because there's no
point
Replace the commented-out print statement with code that does
something with the responseString result.

Resources