Alamofire parse JSON msg and status - ios

I want to display the msg on UITextView using the status, but it display "Success: 200":
{ "status" : 500, "msg" : "\"Information is invalid\"" }
I'm using Swift4 in XCode10, here is my code:
import UIKit
import Alamofire
import SwiftyJSON
class VerifyAccount: UIViewController {
let verify_url = "http://192.168.43.222:3000/mobile/account_verification"
#IBOutlet weak var msgHandler: UITextView!
func postData(url: String , parameters: [String : String]) {
Alamofire.request(url, method: .post, parameters: parameters).responseJSON {
response in
if response.result.isSuccess {
let postJSON : JSON = JSON(response.result.value!)
print(postJSON)
if let status = response.response?.statusCode {
switch(status) {
case 200:
self.msgHandler.text = ("Success: \(status)")
case 500:
self.msgHandler.text = ("Invalid: \(status)")
default:
}
}
} else {
print("Error: \(String(describing: response.result.error))")
}
}
}
#IBAction func verifyBtn(_ sender: Any) {
let compare : [String : String] = ["id" : id , "fname" : fname , "lname" : lname]
postData(url: verify_url , parameters : compare)
}
}

You need to change the way how you handling your response. I've updated your code, it should work.
import UIKit
import Alamofire
import SwiftyJSON
class VerifyAccount: UIViewController {
let verify_url = "http://192.168.43.222:3000/mobile/account_verification"
#IBOutlet weak var msgHandler: UITextView!
func postData(url: String , parameters: [String : String]) {
Alamofire.request(url, method: .post, parameters: parameters).responseJSON {
response in
switch response.result {
case .success:
print("server response: \(response.value!)")
do {
if var json = try JSONSerialization.jsonObject(with: response.data!, options: []) as? [String:Any] {
// Get value by key
var message = "";
if let msg = json["msg"] as? String
{
message = msg; // your message is here, you can do anything with it, whatever you want.
}
var status = 0;
if let st = json["status"] as? Int
{
status = st;
}
}
} catch let error as NSError {
}
break
case .failure(let error):
self.delegate.APIOnError(requestCode: requestCode);
print("server error: \(error.localizedDescription)")
}
}
}

You can get a value safely (whether it's a String, Int, etc...) from your JSON object like so:
let status = postJSON["status"].int ?? 0
let message = postJSON["msg"].string ?? "No Message"
The (??) double question mark gives you the ability to provide a default value in case your parsing fails to get an Int or String

Parse your response data like
guard data _ = response.result.value as? [String: Any] else {
print("Error: \(String(describing: response.result.error))")
return
}
let message = data["msg"] as? String ?? "Unable to parse message"
if let statusCode = data["status"] as? Int {
switch statusCode {
case 200: self.msgHandler.text = ("Success: \(message)")
case 500: self.msgHandler.text = ("Invalid: \(message)")
default:self.msgHandler.text = ("Invalid status code")
}
}

You were using wrong data to parse. You can try this:
if let status = response.response?.statusCode, let message = postJSON['msg'] {
switch(status) {
case 200:
self.msgHandler.text = ("Success: \(message)")
case 500:
self.msgHandler.text = ("Invalid: \(message)")
default:
}
}

Related

passing data (json) to another controller in swift 5.2 con Alamofire

I have a Login view that asks for a card and password. I consult an API and if the entered data is correct, it sends me a JSON like this. Which return has the button method? How do I send that data to the other view? I occupy Alamofire 5.0 and have my Model class.
#IBAction func myButtonIngresarAction(_ sender: Any) {
guard let carnet = self.txtCarnet.text else {return}
guard let contrasena = self.txtPassword.text else {return}
let ingresologinmodel = IngresoLoginModel(usuario: carnet, password: contrasena)
self.apiCall(IngresoLoginModel: ingresologinmodel){
(result) in
switch result{
case .success(let json):
print(json)
**//This is where I want to send that json with the data to the other view. ******
case .failure(let err):
print(err.localizedDescription)
}
}
}
enum ApiErros: Error {
case custom(message : String)
}
typealias Handler = (Swift.Result<Any?, ApiErros>) -> Void
func apiCall(IngresoLoginModel: IngresoLoginModel, completionHandler: #escaping Handler)
{
let header: HTTPHeaders = [
.contentType("application/json")
]
AF.request("https://url/xxxx/api/Login", method: .post, parameters: IngresoLoginModel,
encoder: JSONParameterEncoder.default, headers: header).response{ response in
debugPrint(response)
switch response.result{
case .success(let data):
do{
let json = try JSONDecoder().decode([LoginModel].self, from: data!)
print(json)
if response.response?.statusCode == 200{
completionHandler(.success(json))
}else{
completionHandler(.failure(.custom(message: "Por favor verifica tu internet")))
}
}
catch
{
print(error)
completionHandler(.failure(.custom(message: "Problemas")))
}
case .failure(let err):
print(err.localizedDescription)
}
}
}
Class model
struct LoginModel: Codable {
let idEmpleado: Int
let Nombre: String
let CodEmpleado: String
let password: String
let idPerfil: Int
let activo: Int
let Descripcion: String
let idRegion: Int
let correo: String
}
This is the json that the Api sends me the data changes them for these example
{
"idEmpleado": 1,
"nombre": “test”,
"codEmpleado": “000000”,
"password": “123”,
"idPerfil": 4,
"activo": 1,
"Descripcion": “test”,
"idregion": 1,
"correo": “test#test.com"
}
many way like create a variable to save this json in OtherViewController and call, self?.otherViewController.json = json
https://learnappmaking.com/pass-data-between-view-controllers-swift-how-to/
use didSet
var page = [Datas]() {
didSet {
self.myVariable = page[0].date!
}
}
typealias Handler = (Swift.Result <[LoginModel]?, ApiErros>) -> Void
#IBAction func myButtonIngresarAction(_ sender: Any) {
guard let carnet = self.txtCarnet.text else {return}
guard let contrasena = self.txtPassword.text else {return}
let ingresologinmodel = IngresoLoginModel(usuario: carnet, password: contrasena)
self.apiCall(IngresoLoginModel: ingresologinmodel){
(result) in
switch result{
case .success(let json):
print(json)
//Here is that I do not know how to send it to the other controller all the json
let viewControllerB = HomeMenuViewController()
viewControllerB.datosPersonales = json!
self.navigationController?.pushViewController(viewControllerB, animated: true)
case .failure(let err):
print(err.localizedDescription)
}
}
}
second controller
class HomeMenuViewController: UIViewController {
#IBOutlet weak var mylabel: UILabel!
var datosPersonales = [LoginModel]()
override func viewDidLoad() {
super.viewDidLoad()
print("***************")
print(datosPersonales)
print("***************")
}
}

respsonse Handling problem in ios, alamofire

I try to make an API call with alamofire. when I print response.value like this print(response.value ?? "") I get correct text in Xcode console, but I get an error this line comletionHanlder(response.value as! [Order]).
error message is Could not cast value of type '__NSDictionaryI' (0x7f81db0f3070) to 'AppName.Order' (0x10db3fb80)
static func getOrders( comletionHanlder: #escaping ([Order]) -> Void){
let headers : HTTPHeaders = ["Authorization" : "Bearer \(User.current!.accessToken)",
"Lang" : "KA"]
let urlStr = Constants.Api.baseUrl + Constants.Api.Routes.api + Constants.Api.Routes.doctorBooking + Constants.Api.Routes.getBookings
AF.request(urlStr,
method: .post,
encoding: JSONEncoding.default,
headers: headers).responseJSON{ response in
if response.response?.statusCode == 400 {
comletionHanlder([])
} else {
if response.response?.statusCode == 200 {
print(response.value ?? "")
comletionHanlder(response.value as! [Order])
}
}
}
;
struct Order: Codable {
let title: String
let details: String
let BookingId: Int
}
when I print response.value, I got this message
(
{
title = "title"
details = "details"
BookingId = 10002
},
{
title = "title1"
details = "details1"
BookingId = 10003
}
)
As stated on the error message, casting the response.value to Order won't work. You should use the JSONDecodable class to decode the response to the desired list of orders like this:
guard let responseData = response.data else { /* do something */ }
do {
let orders = try JSONDecoder().decode([Order].self, from: responseData)
debugPrint(orders)
} catch {
// handle the error
}

How to parse JSON dictionary using SwiftyJSON and Alamofire

I have a problem with my alamofire.request. I tried to to decode JSON response with Struct using SwiftyJSON.
. But my model data is getting nil.
here is my API response
{
"userDetails" :
{ "id":2,
"roleID":1,
"successFlag":1
},
"settingID" : "20"
}
Model class
import Foundation
import SwiftyJSON
struct User {
var settingID : String?
var userdetails : UserDetails?
init(json : JSON?) {
self.settingID = json?["settingID"].string
if let value = json?["userDetails"].dictionaryObject {
let new = UserDetails(json: JSON(value))
self.userdetails = new
}
}
}
struct UserDetails {
var id : Int?
var roleID : Int?
var successFlag : Int?
init(json : JSON?) {
self.id = json?["id"].int
self.roleID = json?["roleID"].int
self.successFlag = json?["successFlag"].int
}
}
My code for Data fetching using Alamofire and SwiftyJSON
import Alamofire
import SwiftyJSON
var userData : [User] = []
func fetchData() {
Alamofire.request(base_url + APIManager.loginApi, method: .post, parameters: params, encoding: URLEncoding.queryString, headers: nil).responseJSON { (resp) in
switch resp.result {
case .success :
print(resp.result)
do {
let myResult = try JSON(data: resp.data!)
print(myResult)
myResult.dictionaryValue.forEach({(user) in
let newUser = User(json: JSON(user))
self.userData.append(newUser)
print(self.userData)
})
}catch {
print(error)
}
break
case .failure :
break
}
}
}
But if i print self.userData , getting nill response.
Have you any idea why I can't decode my struct with my JSON data?.
Thanks a lot for your help
Try using Codable instead. It is easier to create a Codable model and is Apple recommended.
struct Root: Decodable {
let userDetails: User
let settingID: String
}
struct User: Decodable {
let id: Int
let roleID: Int
let successFlag: Int
}
Parse the data like,
do {
let response = try JSONDecoder().decode(Root.self, from: data)
print(response)
} catch {
print(error)
}
Change your response code like below
switch response.result {
case .success(let value):
let response = JSON(value)
print("Response JSON: \(response)")
let newUser = User(json: response)
self.userData.append(newUser)
print(self.userData)
case .failure(let error):
print(error)
break
}

Alamofire Web service manager returns nil in viewController

I want to create AlamofireWebService manager that contains all of my requests and I just use class functions of this class in my viewControllers and use responses in the viewController.
For example something like this in viewController:
let cardResponse : String?
cardResponse = WebServiceManager.shared.getCardTitle()
I searched and found I should use escaping completionHandler in my function, And I wrote this:
import Foundation
import Alamofire
import SwiftyJSON
class WebServiceManager {
static let shared : WebServiceManager = WebServiceManager()
let apiEndPoint = "My URL"
func getCardTitle(completionHandler: #escaping (NSDictionary?, Error?) -> ()) {
Alamofire.request("\(apiEndPoint)")
.responseJSON { response in
switch response.result {
case .success(let value):
print("from .success \(value)")
completionHandler(value as? NSDictionary, nil)
case .failure(let error):
completionHandler(nil, error)
}
}
}
}
In success case, print works fine but in viewController, it just prints nil.
My viewController:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
WebServiceManager.shared.getCardTitle() { responseObject, error in
// use responseObject and error here
print("responseObject = \(responseObject); error = \(error)")
return
}
}
What should I do to print in viewController print my response?
It means that your value can't be cast to NSDictionary it has another type.
completionHandler(value as? NSDictionary, nil)
Please try in the manager a "pseudo code"
if let dic = value as? [String: Any] {
debugPrint("Dic \(dic)")
} else if let str = value as? String {
debugPrint("String \(str)")
} else if let data = value as? Data, let str = String(data: data, encoding: .utf8) {
debugPrint("UTF8 String \(str)")
}
just check response nil
Alamofire.request("URL", method: .post).responseJSON{(responseData) -> Void in
if((responseData.result.value != nil)){
let jsonData = JSON(responseData.result.value)
if let arrJSON = jsonData["keyNodes"].arrayObject {
for index in 0...arrJSON.count-1 {
let aObject = arrJSON[index] as! [String : AnyObject]
var sl:String;
if let sl1 = aObject["sl"] as? String {
sl = sl1;
}
}
}
}
}

Deserialize a JSON array to a Swift array of objects

I am new to Swift, and am not able to figure out how to deserialize a JSON array to an array of Swift objects. I'm able to deserialize a single JSON user to a Swift user object fine, but just not sure how to do it with a JSON array of users.
Here is my User.swift class:
class User {
var id: Int
var firstName: String?
var lastName: String?
var email: String
var password: String?
init (){
id = 0
email = ""
}
init(user: NSDictionary) {
id = (user["id"] as? Int)!
email = (user["email"] as? String)!
if let firstName = user["first_name"] {
self.firstName = firstName as? String
}
if let lastName = user["last_name"] {
self.lastName = lastName as? String
}
if let password = user["password"] {
self.password = password as? String
}
}
}
Here's the class where I'm trying to deserialize the JSON:
//single user works.
Alamofire.request(.GET, muURL/user)
.responseJSON { response in
if let user = response.result.value {
var swiftUser = User(user: user as! NSDictionary)
}
}
//array of users -- not sure how to do it. Do I need to loop?
Alamofire.request(.GET, muURL/users)
.responseJSON { response in
if let users = response.result.value {
var swiftUsers = //how to get [swiftUsers]?
}
}
The best approach is the use Generic Response Object Serialization provided by Alamofire here is an example :
1) Add the extension in your API Manager or on a separate file
public protocol ResponseObjectSerializable {
init?(response: NSHTTPURLResponse, representation: AnyObject)
}
extension Request {
public func responseObject<T: ResponseObjectSerializable>(completionHandler: Response<T, NSError> -> Void) -> Self {
let responseSerializer = ResponseSerializer<T, NSError> { request, response, data, error in
guard error == nil else { return .Failure(error!) }
let JSONResponseSerializer = Request.JSONResponseSerializer(options: .AllowFragments)
let result = JSONResponseSerializer.serializeResponse(request, response, data, error)
switch result {
case .Success(let value):
if let
response = response,
responseObject = T(response: response, representation: value)
{
return .Success(responseObject)
} else {
let failureReason = "JSON could not be serialized into response object: \(value)"
let error = Error.errorWithCode(.JSONSerializationFailed, failureReason: failureReason)
return .Failure(error)
}
case .Failure(let error):
return .Failure(error)
}
}
return response(responseSerializer: responseSerializer, completionHandler: completionHandler)
}
}
public protocol ResponseCollectionSerializable {
static func collection(response response: NSHTTPURLResponse, representation: AnyObject) -> [Self]
}
extension Alamofire.Request {
public func responseCollection<T: ResponseCollectionSerializable>(completionHandler: Response<[T], NSError> -> Void) -> Self {
let responseSerializer = ResponseSerializer<[T], NSError> { request, response, data, error in
guard error == nil else { return .Failure(error!) }
let JSONSerializer = Request.JSONResponseSerializer(options: .AllowFragments)
let result = JSONSerializer.serializeResponse(request, response, data, error)
switch result {
case .Success(let value):
if let response = response {
return .Success(T.collection(response: response, representation: value))
} else {
let failureReason = "Response collection could not be serialized due to nil response"
let error = Error.errorWithCode(.JSONSerializationFailed, failureReason: failureReason)
return .Failure(error)
}
case .Failure(let error):
return .Failure(error)
}
}
return response(responseSerializer: responseSerializer, completionHandler: completionHandler)
}
}
2) update your model object like this:
final class User: ResponseObjectSerializable, ResponseCollectionSerializable {
let username: String
let name: String
init?(response: NSHTTPURLResponse, representation: AnyObject) {
self.username = response.URL!.lastPathComponent!
self.name = representation.valueForKeyPath("name") as! String
}
static func collection(response response: NSHTTPURLResponse, representation: AnyObject) -> [User] {
var users: [User] = []
if let representation = representation as? [[String: AnyObject]] {
for userRepresentation in representation {
if let user = User(response: response, representation: userRepresentation) {
users.append(user)
}
}
}
return users
}
}
3) then you can use it like that :
Alamofire.request(.GET, "http://example.com/users")
.responseCollection { (response: Response<[User], NSError>) in
debugPrint(response)
}
Source: Generic Response Object Serialization
Useful Link: Alamofire JSON Serialization of Objects and Collections
Since you are using Alamofire to make your requests why don't you give a chance to Hearst-DD ObjectMapper it has an Alamofire extension AlamofireObjectMapper. I think it'll save you time!
I would loop through them then add each user to an array (preferably a property of the VC and not an instance variable) but here is an example.
Alamofire.request(.GET, "YourURL/users")
.responseJSON { response in
if let users = response.result.value {
for user in users {
var swiftUser = User(user: user as! NSDictionary)
//should ideally be a property of the VC
var userArray : [User]
userArray.append(swiftUser)
}
}
}
You could also try EVReflection https://github.com/evermeer/EVReflection
It's even more simple, i.e. to parse JSON (code snippet taken from EVReflection link):
let json:String = "{
\"id\": 24,
\"name\": \"Bob Jefferson\",
\"friends\": [{
\"id\": 29,
\"name\":
\"Jen Jackson\"}]}"
you can use this class:
class User: EVObject {
var id: Int = 0
var name: String = ""
var friends: [User]? = []
}
in this way:
let user = User(json: json)

Resources