Antonio Labra
Antonio Labra

Reputation: 2000

Parsing Failed: JSONDecoder Swift

I'm trying to decode a json request using Alamofire 5.2 The problem is that I use JSONDecoder and I have some issues about the conversion

The API is in Spanish and my models in English so I decided to changed this kind of values using an enum of keys

But I don't know if this works... Here's my code:

API RESPONSE: (json variable)

    {
  "sistemaOperativoId" : 0,
  "nombreUsuario" : "Coasnf_09",
  "menus" : [

  ],
  "acciones" : [

  ],
  "fechaRegistro" : "2020-04-15T09:46:24.0573154",
  "empresa" : null,
  "version" : null
}

MY MODEL:

struct UserP: Decodable{
    var username : String
    var company : String

    private enum CodingKeys: String, CodingKey{
        case username = "nombreUsuario"
        case company = "empresa"
    }

    init(from decoder: Decoder) throws{
        let container = try decoder.container(keyedBy: CodingKeys.self)
        username = try container.decode(String.self, forKey: .username) ?? "null"
        company = try container.decode(String.self, forKey: .company)  ?? "null"
    }

    init(username: String, company: String){
        self.username = username
        self.company = company
    }
}

CONVERTION:

   func login(user: User) -> UserP? {
        var userData: UserP! = nil
        AF.request(UserRouter.login(user: user)).responseJSON{ response in
            switch response.result {
            case .success(let response):
                print(response)
                let dict = (response as? [String : Any])!
                let json = dict["data"] as! [String: Any]

                if let jsonData = try? JSONSerialization.data(withJSONObject: json , options: .prettyPrinted)
                {
                    do {
                        var jsonString = String(data: jsonData, encoding: String.Encoding.utf8)!
                        print(jsonString)
                        userData = try JSONDecoder().decode(UserP.self, from: Data(jsonString.utf8))
                        print("Object Converted: ", userData.username)
                    } catch {
                        print("Parsing Failed: ", error.localizedDescription)
                    }
                }



                break

            case .failure(let error):
                print(error)
                break
            }
        }

        return userData
    }

Upvotes: 1

Views: 493

Answers (1)

staticVoidMan
staticVoidMan

Reputation: 20234

Alamofire logic related change:

response from Alamofire has a data property that you can use directly:

let json = response.data
do {
    let user = try JSONDecoder().decode(UserP.self, from: json)
    print(user)
}
catch {
    print(error)
}

Furthermoe, if the keys nombreUsuario and empresa are not guaranteed to come in the json then recommended way is to mark those variables as optional. With this you don't need the custom decoder logic.

Model Change #1:

struct UserP: Decodable {
    var username: String?
    var company: String?

    private enum CodingKeys: String, CodingKey{
        case username = "nombreUsuario"
        case company = "empresa"
    }
}

Model Change #2:

If you want to give some default values then a custom decoder can help:

struct UserP: Decodable {
    var username: String
    var company: String

    private enum CodingKeys: String, CodingKey{
        case username = "nombreUsuario"
        case company = "empresa"
    }

    init(from decoder: Decoder) throws{
        let container = try decoder.container(keyedBy: CodingKeys.self)
        username = try container.decodeIfPresent(String.self, forKey: .username) ?? "Default Name"
        company = try container.decodeIfPresent(String.self, forKey: .company) ?? "Default Company Name"
    }
}

Upvotes: 1

Related Questions