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.
Related
I have been working in google poly line functionality. I have initialised the URL and I have used alamofire request. Everything with the URL is working fine but I could not draw the line and it was stating like invalid URL.
I have attached the code which I have tried.
let urlString = "https://maps.googleapis.com/maps/api/directions/json?origin=\(pickupcordinates)&destination=\(dropCoordinates)&mode=driving&key=AIzaSyDJUX9uBiZivQGlAu1KTUC1kcmaiAnI270"
Alamofire.request(urlString,method: .get, parameters: nil,encoding: JSONEncoding.default, headers: nil).responseJSON {
response in
switch response.result {
case .success:
print(response)
break
case .failure(let error):
print(error)
}
}
invalidURL(url: "https://maps.googleapis.com/maps/api/directions/json?origin=13.03589205752495,80.25411217280107&destination=13.0277895999, 80.22673778239999&mode=driving&key=AIzaSyDJUX9uBiZivQGlAu1KTUC1kcmaiAnI270")
The above is my console response error
I want to draw a poly line from my source to destination.
I am using this way give it a try. May help you.
func drawPath(source: CLLocationCoordinate2D, destination: CLLocationCoordinate2D){
let orgin = "\(source.latitude),\(source.longitude)"
let destin = "\(destination.latitude),\(destination.longitude)"
let url = "https://maps.googleapis.com/maps/api/directions/json?origin=\(orgin)&destination=\(destin)&mode=driving"
Alamofire.request(url).responseJSON { response in
switch response.result {
case .success:
let json = JSON(data: response.data!)
let routes = json["routes"].arrayValue
print(response)
break
case .failure(let error):
print(error)
}
}
}
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)
}
}
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;
}
My JSON response in postman looks like this...
{
"success": 1,
"Details": {
"seller_id": "165",
"mobile_no": "9653265987",
"seller_name": "User A",
"seller_email_id": "user#gmail.com",
"company_name": "myCompany",
"category": "Cosmetics",
"otp": "1111"
},
"message": "Seller Already Registered!!!"
}
Now I wanted to give a condition based on whether success is 0 or 1 and so for that I wanted to extract success. Also I want to extract mobile number. But I am not able figure out how to do that.
This is how I am making my Alamofire post request...
Alamofire.request(url, method: .post, parameters: Parameters, encoding: URLEncoding.httpBody, headers: headers)
.responseString { (response) in
if let httpResponse = response.response {
print("error \(httpResponse.statusCode)")
if httpResponse.statusCode == 200 {
//Do something
}
}
}
I did go through similar issues raised by other users...but couldn't find from them an exact solution for my issue...
Try this
Alamofire.request(url, method: .post, parameters: Parameters, encoding: URLEncoding.httpBody, headers: headers)
.responseJSON { (response) in
switch response.result{
case .success(_):
print("Success: \(response)")
let JsonResponse = response.result.value as? [String: Any]
if JsonResponse?["success"] as! Int == 1{
let dict = JsonResponse?["Details"] as! [String : Any]
let mobileNo = dict["mobile_no"] as! String
}
else{
print("Failed")
}
case .failure(let error):
print("Failed: \(error)")
}
}
There are a couple of issues:
Your parameters to request don't look quite right.
the parameters parameter doesn't look right: at best, it's very strange to have a Parameters variable (you should use lower case for variables; and this conflicts with an Alamofire type);
the encoding should be URLEncoding.default. Or, because URLEncoding.default is the default value, you can omit this altogether.
If you want to check for status code, let validate do that for you.
If you're expecting JSON in response, use reponseJSON instead of responseString.
Use if let or guard let with as? to safely unwrap optionals. Do not use as! (unless you are 100% sure that it never could fail ... and when dealing with responses from a remote server, you can never be 100% confident).
Thus:
func performRequest(url: String, parameters: [String: String]?, headers: [String: String]?) {
Alamofire.request(url, method: .post, parameters: parameters, headers: headers)
.validate(statusCode: 200 ..< 300)
.responseJSON { response in
switch response.result {
case .success(let value):
guard let dictionary = value as? [String: Any],
let success = dictionary["success"] as? Int else {
print("success not found")
return
}
guard success == 1 else {
print("web service reported failure")
return
}
guard let details = dictionary["Details"] as? [String: Any] else {
print("Did not find details")
return
}
guard let mobile = details["mobile_no"] as? String else {
print("mobile not found")
return
}
print(mobile)
case .failure(let error):
print("Failed: \(error)")
}
}
}
Or, in your comment below, if you want to goToSignUpScreen() if success was 0, then:
Alamofire.request(url, method: .post, parameters: parameters, headers: headers)
.validate(statusCode: 200 ..< 300)
.responseJSON { response in
switch response.result {
case .success(let value):
guard let dictionary = value as? [String: Any],
let success = dictionary["success"] as? Int else {
print("success not found")
return
}
if success == 0 {
self.goToSignUpScreen()
}
case .failure(let error):
print("Failed: \(error)")
}
}
I have a question about the new version of Alamofire for Swift 2
Alamofire.request(.POST, urlString, parameters: parameters as? [String : AnyObject])
.responseJSON { (request, response, result) -> Void in
let dico = result as? NSDictionary
for (index, value) in dico! {
print("index : \(index) value : \(value)")
}
}
In this section I would like to cast the result in to a NSDictionary. But When I compile and put a breakpoint, the debugger says that dico is nil. If I use debugDescription to print result, it is not nil and contains what I expected
How can I cast the Result variable?
The accepted answer works great but with the introduction of Alamofire 3.0.0 there are some breaking changes that affects this implementation.
The migration guide has further explanations but i will highlight the ones related to the actual solution.
Response
All response serializers (with the exception of response) return a generic Response struct.
Response type
The Result type has been redesigned to be a double generic type that does not store the NSData? in the .Failure case.
Also take in count that Alamofire treats any completed request to be successful, regardless of the content of the response. So you need to chain a .validate() before .responseJSON() to hit the .Failure case.
Read more about it here.
Updated code:
let url = "http://api.myawesomeapp.com"
Alamofire.request(.GET, url).validate().responseJSON { response in
switch response.result {
case .Success(let data):
let json = JSON(data)
let name = json["name"].stringValue
print(name)
case .Failure(let error):
print("Request failed with error: \(error)")
}
}
For reference:
Xcode 7.3 (Swift 2.2)
Alamofire 3.3.1
SwiftyJSON 2.3.3
If you don't mind using SwiftyJSON library, here's a working example in Xcode 7 Beta 5 + Alamofire 2.0.0-beta.1 + SwiftyJSON (xcode7 branch)
Alamofire.request(.GET, url, parameters: params, encoding: ParameterEncoding.URL).responseJSON { (_, _, result) in
switch result {
case .Success(let data):
let json = JSON(data)
let name = json["name"].string
case .Failure(_, let error):
print("Request failed with error: \(error)")
}
}
Edit:
Updated SwiftyJSON git page
You can now achieve most of the required behaviour out of the box without the need for SwiftyJSON for example. My OAuthTokenResponse is a simple struct that is Codable. The Alamofire library 5.2.2 lets you respond using the 'responseDecodable'
If you have say a struct that looks like this:
struct OAuthTokenResponse : Codable
{
var access_token:String?
var token_type:String?
var expires_in:Int?
var scope:String?
}
And then in your network call (using Alamofire)
let request = AF.request(identityUrl, method: .post, parameters: parameters, encoding: URLEncoding.httpBody)
request
.validate()
.responseDecodable { (response:AFDataResponse<OAuthTokenResponse>) in
switch response.result {
case .success(let data):
do {
let jwt = try decode(jwt: data.access_token!) // example
self.connected = true
print(jwt)
} catch {
print(error.localizedDescription)
self.connected = false
}
case .failure(let error):
self.connected = false
print(error.localizedDescription)
}
}
In the above code, the success case automatically deserialises your JSON using the decodable protocol into your struct. Any errors will result in the error case being hit instead.