getting data from AF.Request response - ios

I need the data from the json response from my Post request call using Alamofire but I cannot access that data for some reason
I tried following along with Alamofire github documentation along with this post get data from AF responseJSON. but neither have helped me.
AF.request("https://mbd.cookcountysupernetwork.com/ap/swift_math_get.asp", method: .post, parameters: parameters, encoding: JSONEncoding.default)
.responseJSON { response in
print(response)
print("floop")
}
This is what I see when the code runs
success({
Operand = (
{
A = 12;
},
{
B = 25;
}
);
Operation = Multiply;
Result = 300;
})
so I know the json is there, i just need to access the "Result = 300" so I can set a text box to say "300". but I tried many different methods and I cannot access the information I need from response. Also i do not have a response.result.value which is what almost every post I see about this says to use.

You can access the Result value as,
AF.request("https://mbd.cookcountysupernetwork.com/ap/swift_math_get.asp", method: .post, parameters: parameters, encoding: JSONEncoding.default)
.responseJSON { response in
switch response.result {
case .success(let value):
if let json = value as? [String: Any] {
print(json["Result"] as? Int)
}
case .failure(let error):
print(error)
}
}

Related

I am getting an empty byte array as result for an API call which is expected to return a png image

I am using Alamofire for making the network call. It was expected to return a png image. But from iOS app I am not able to fetch the image, http response is success but getting an empty byte array. I have tried using Postman and from there I am able to see the image as the response. Following is my code snippet.
var imageParams: [String: Any] = [:]
imageParams["pois"] = ["start,-37.811581918854074,144.9472252859507","stop,-37.821561918854074,145.9472252859507", "stop,-37.711581918854074,144.9472252859507","stop,-37.751581918854074,144.9472252859507", "end,-37.941581918854074,144.9472252859507"]
Alamofire.request("http://192.168.43.210:8086/v1/location/getHsMapImage",
method: .post,
parameters: imageParams,
encoding: URLEncoding.httpBody,
headers: ["Content-Type": "application/json"]).responseString { (response) in
switch(response.result) {
case .success(_):
if let data = response.result.value{
print(response.result.value)
}
break
case .failure(_):
print(response.result.error)
break
}
}

How to access alamofire response

I'm new to iOS and I have some Swift code in app that's supposed to switch cases depending on the error message that I receive from the server. The message is wrapped and I'm having trouble getting to it. Here's the code
func sendAlamofireRequest(submissionURL: URL, parameters: Parameters, chosenTracker: String) -> String {
var outputMessage = ""
Alamofire.request(submissionURL, method: .post, parameters: parameters, encoding: JSONEncoding.default).validate().responseString() {
response in
switch response.result {
case .success:
print("Validation Successful...\(String(describing: response.value))")
print("response value: \(String(response.value!))")
switch response.value {
case "error_none"?:
outputMessage = "No matching Group Code. If you are having trouble, please go to \nhttps://app.phillyscientists.com"
break
case "error_tooManyIDs"?:
outputMessage = "Error, please contact developer."
break
case "error_noGroupIDReceived"?:
outputMessage = "Try Again."
break
default:
let JSONResponse : JSON = JSON.init(parseJSON: response.result.value!)
//uncomment this section for debugging
// print("=================<JSON RESP>=================");
// print(JSONResponse)
// print("=================</JSON RESP/>=================");
//
let teacherNameGot = self.parseJSONData(json: JSONResponse, trackerValuePassed: chosenTracker)
self.saveJSONDataToUserDefaults(teacher: teacherNameGot)
// outputMessage = "Logged In Successfully!"
break
}
case .failure(let error):
outputMessage = String(error.localizedDescription)
print(outputMessage)
}
}
return outputMessage
}
Here's the output from console:
Validation Successful...Optional("{\"Error\":\"error_none\"}")
response value: Optional("{\"Error\":\"error_none\"}")
How do I get to the value so that the switch case actually starts working?
Thanks!
you can use Alamofire method .responseJSON which will give you an http object that has several attributes like request and response. Take this code as an example:
Alamofire.request("https://your-service-url.com/api", method: .post, parameters: paremeters, encoding: JSONEncoding.default, headers: headers).responseJSON{ (data) in
guard let statusCode = data.response?.statusCode, statusCode == 200, let result = data.result.value as? [[String: Any]] else{
print("Error with HTTP status \(data.response?.statusCode ?? 0)")
return
}
var events : [Event] = []
result.forEach({ (rawEvent) in
events.append(Event(from: rawEvent))
})
handler(events, statusCode)
}
Notice how I play there with the objects that .responseJSON provides, and how I get the resulting array from the service by accessing data.result.value (that being said this will depend on the data structure of your service response)
It seems that the output is in Json, so i'll need to map it into an object(or class,whatever you call it). If you think its not worth it, you can convert it into an Dictionary, i think it will work as well
#Gustavo caiafa is right, Mapping it to JSON did the trick. Here's the code for anyone who gets stuck on something similar:
Alamofire.request(submissionURL, method: .post, parameters: parameters, encoding: JSONEncoding.default).validate().responseString() { (response) in
let outputResponseJSON : JSON = JSON.init(parseJSON: response.result.value!)
let outputResponseText = JSON(outputResponseJSON)["Error"].stringValue
switch response.result {
case .success:
print("Validation Successful...\(String(describing: response.value))")
print("response value: \(String(describing: String(outputResponseText)))")
switch outputResponseText {
case "error_none":
outputMessage = "No matching Group Code. If you are having trouble, please go to \nhttps://app.phillyscientists.com"
print(outputMessage)
break
case "error_tooManyIDs":
outputMessage = "Error, please contact developer."
print(outputMessage)
break
case "error_noGroupIDReceived":
outputMessage = "Try Again."
print(outputMessage)
break
default:
let JSONResponse : JSON = JSON.init(parseJSON: response.result.value!)
The answer is using SwiftyJSON for the outputResponseJSON and outputResponseText values.

Alamofire (json, request, delay)

i have a json request and my problem is that the response from the server does not have time to come and because of this I get an error because I'm working with data (in viewdidload()) which is not yet available. I tried to read about synchronous and asynchronous requests but I don't understand how to do them.
in viewDidLoad() i call my fucn which is call to the my server and i wait a json, after executing the function, I start working with the data that should come , But the code does not wait for the moment when they come and go further. Can I specify a delay or something like that?
Alamofire.request(url, method: .post, parameters: params, encoding: JSONEncoding.default, headers: headers).responseJSON {
(response: DataResponse) in
switch(response.result) {
case .success(let value):
let json = JSON(value)
for index in 0 ..< json["items"].count {
let path = json["items"][index]
self.Data.append(ProfileModel())
self.Data[index].name = path["name"].stringValue
self.Data[index].email = path["email"].stringValue
self.Data[index].created = path["created"].double!
self.tableView.reloadData()
}
DispatchQueue.main.async {
}
case .failure(let error):
print(error)
break
}
}.resume()
}

Error while parsing JSON data received via Alamofire (Swift)

I'm working with a non-profit organisation to help them develop a mobile application for their website (so they provided me with the backend services, etc)
Their login PHP service accepts data in JSON, and returns a true or false value in the form of JSON data, but I'm having trouble processing the response in Swift. I'm using Alamofire to connect to the HTTP service.
I'm attaching my code and the exception message I'm receiving below, would really appreciate some help
func authenticateUser (un: String, pw: String) -> Bool
{
var checker = false
let jsonDict : [String: String] = ["volunteer_email": un, "volunteer_pass": pw]
Alamofire.request("www.sampleurl.com/login.php", method: .post, parameters: jsonDict, encoding: JSONEncoding.default, headers: nil).responseJSON { (response:DataResponse<Any>) in
switch(response.result) {
case .success(_):
if response.result.value != nil{
print (response.result.value)
let resp = response.result.value as! NSDictionary
let results = resp["status"] as! [[String:Any]]
//Change the boolean value of checker based on the value of the results constant
print (results)
}
break
case .failure(_):
print(response.result.error)
break
}
}
return checker;
}
Log:
Optional(<__NSSingleObjectArrayI 0x600000009b50>( {
status = false; } ) ) Could not cast value of type '__NSSingleObjectArrayI' (0x10e28c528) to 'NSDictionary'
(0x10e28d1a8). 2018-05-09 12:13:00.177091+0530 TestApp1 [16680:817883]
Could not cast value of type '__NSSingleObjectArrayI' (0x10e28c528) to
'NSDictionary' (0x10e28d1a8). (lldb)
Log for response.result.value:
Note: "status":"false"/"true" is the output from the web service
Optional(<__NSSingleObjectArrayI 0x60400001b160>(
{
status = false;
}
))
Note: I did some research and I understood what the NSSingleObjectArray is and what causes it, but I'm stuck here as the service passes back only a single JSON value to my app. Is there any way to handle this without requesting the organisation to change their code? Logically, shouldn't I be able to cast the response into an NSDictionary regardless of its size?
Also, the reason why I've specified that the returned data can be of type any, is because I ran into an issue that can be found here:
Other StackOverflow question
Thanks so much in advance :)
Since you're using .responseJSON of Alamofire, you should make use of Alamofire's parameterized enums. It provides the json object in .success. So doing case .success(_) is wasteful.
Go ahead with this and no need of typecasting response.result.value at all.
Alamofire
.request("www.sampleurl.com/login.php",
method: .post,
parameters: jsonDict,
encoding: JSONEncoding.default,
headers: nil)
.responseJSON { (response) in
switch(response.result) {
case .success(let responseJSON):
print(responseJSON)
/*
As an improvement:
To obtain an easy-access object, convert responseJSON to either a:
1. Codable model:
let model = JSONDecoder().decode(SomeModel.self,
from: responseJSONData)
2. SwiftyJSON object: (available on GitHub)
let json = JSON(responseJSON)
Doing so will basically make accessing the inner elements easier.
*/...
case .failure(let error):
print(error)
}
}
BTW, just FYI: the response is an array of dictionaries, not a dictionary of array of dictionaries.
Use NSArray instead of NSDictionary
func authenticateUser (un: String, pw: String) -> Bool{
var checker = false
let jsonDict : [String: String] = ["volunteer_email": un, "volunteer_pass": pw]
Alamofire.request("www.sampleurl.com/login.php", method: .post, parameters: jsonDict, encoding: JSONEncoding.default, headers: nil).responseJSON { (response:DataResponse<Any>) in
switch(response.result) {
case .success(_):
if response.result.value != nil{
print (response.result.value)
let resp = response.result.value as! NSArray
let results = resp["status"] as! [[String:Any]]
//Change the boolean value of checker based on the value of the results constant
print (results)
}
break
case .failure(_):
print(response.result.error)
break
}
}
return checker;
}

Alamofire returns .Success on error HTTP status codes

I have a pretty simple scenario that I'm struggling with. I'm using Alamofire to register a user on a rest API. The first call to register is successful and the user can log in. The second call, when trying to register with the same email address should result in a HTTP status code 409 from the server. Alamofire, however, returns a .Success with an empty request and response. I have tested this this API with postman and it correctly returns a 409.
Why is Alamofire not returning .Failure(error), where the error has status code info etc?
Here is the call I run with the same input each time.
Alamofire.request(.POST, "http://localhost:8883/api/0.1/parent", parameters: registrationModel.getParentCandidateDictionary(), encoding: .JSON).response(completionHandler: { (req, res, d, e) -> Void in
print(req, res, d, e)
})
From the Alamofire manual:
Validation
By default, Alamofire treats any completed request to be successful,
regardless of the content of the response. Calling validate before a
response handler causes an error to be generated if the response had
an unacceptable status code or MIME type.
You can manually validate the status code using the validate method, again, from the manual:
Alamofire.request(.GET, "https://httpbin.org/get", parameters: ["foo": "bar"])
.validate(statusCode: 200..<300)
.validate(contentType: ["application/json"])
.response { response in
print(response)
}
Or you can semi-automatically validate the status code and content-type using the validate with no arguments:
Alamofire.request(.GET, "https://httpbin.org/get", parameters: ["foo": "bar"])
.validate()
.responseJSON { response in
switch response.result {
case .success:
print("Validation Successful")
case .failure(let error):
print(error)
}
}
If using response, you can check the NSHTTPURLResponse parameter:
Alamofire.request(urlString, method: .post, parameters: registrationModel.getParentCandidateDictionary(), encoding: JSONEncoding.default)
.response { response in
if response.response?.statusCode == 409 {
// handle as appropriate
}
}
By default, 4xx status codes aren't treated as errors, but you can use validate to treat it as an such and then fold it into your broader error handling:
Alamofire.request(urlString, method: .post, parameters: registrationModel.getParentCandidateDictionary(), encoding: JSONEncoding.default)
.validate()
.response() { response in
guard response.error == nil else {
// handle error (including validate error) here, e.g.
if response.response?.statusCode == 409 {
// handle 409 here
}
return
}
// handle success here
}
Or, if using responseJSON:
Alamofire.request(urlString, method: .post, parameters: registrationModel.getParentCandidateDictionary(), encoding: JSONEncoding.default)
.validate()
.responseJSON() { response in
switch response.result {
case .failure:
// handle errors (including `validate` errors) here
if let statusCode = response.response?.statusCode {
if statusCode == 409 {
// handle 409 specific error here, if you want
}
}
case .success(let value):
// handle success here
print(value)
}
}
The above is Alamofire 4.x. See previous rendition of this answer for earlier versions of Alamofire.
if you use validate() you'll loose the error message from server, if you want to keep it, see this answer https://stackoverflow.com/a/36333378/1261547
Here is my code for AlamoFire error catching:
switch response.result {
case .success(let value):
completion(.success(value))
case .failure(var error):
var errorString: String?
if let data = response.data {
if let json = try? (JSONSerialization.jsonObject(with: data, options: []) as! [String: String]) {
errorString = json["error"]
}
}
let error = MyError(str: errorString!)
let x = error as Error
print(x.localizedDescription)
completion(.failure(x))
}
and the MyError class difinition:
class MyError: NSObject, LocalizedError {
var desc = ""
init(str: String) {
desc = str
}
override var description: String {
get {
return "MyError: \(desc)"
}
}
//You need to implement `errorDescription`, not `localizedDescription`.
var errorDescription: String? {
get {
return self.description
}
}
}

Resources