Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Expected to decode Int but found a string

My JSON looks like:

{
    "status": true,
    "data": {
        "img_url": "/images/houses/",
        "houses": [
            {
                "id": "1",
                "name": "Kapital",
                "url": "https://kapital.com/",
                "img": "10fbf4bf6fd2928affb180.svg"
            }
        ]
     }
 }

And I'm using the next structs:

struct ServerStatus: Decodable {
    let status: Bool
    let data: ServerData
}

struct ServerData: Decodable {
    let img_url: String
    let houses: [House]
}

struct House: Decodable {
    let id: Int
    let img: String
    let name: String
    let url: String
}

But when I'm using:

let houses = try JSONDecoder().decode(ServerStatus.self, from: data)

I get the next error:

3 : CodingKeys(stringValue: "id", intValue: nil)
  - debugDescription : "Expected to decode Int but found a string/data instead."

It's my first time using Decodables and I'm googling this problem but was not able to fix it. Can someone help me to find out what's wrong and maybe explain me that?

When I remove data part from the ServerStatus everything works. So the problem is in parsing data part

like image 992
J. Doe Avatar asked Sep 10 '18 21:09

J. Doe


1 Answers

Change you House struct to this:

House: Decodable {
    let id: String
    let name: String
    let url: String
    let img: String
}

id should be a String. And to get the houses:

let houses = try JSONDecoder().decode(ServerStatus.self, from: data).data.houses

If you don't want to change the id coming from the server to Int, you can provide a custom implementation of Encodable and Decodable to define your own encoding and decoding logic.

struct House {
    let id: Int
    let img: String
    let name: String
    let url: String

    enum CodingKeys: String, CodingKey {
        case id, img, name, url
    }
}

extension House: Decodable {
    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        guard let idInt = Int(try values.decode(String.self, forKey: .id)) else {
            fatalError("The id is not an Int")
        }
        id = idInt
        img = try values.decode(String.self, forKey: .img)
        name = try values.decode(String.self, forKey: .name)
        url = try values.decode(String.self, forKey: .url)
    }
}

//Just in case you want to encode the House struct
extension House: Encodable {
    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(String(id), forKey: .id)
        try container.encode(img, forKey: .img)
        try container.encode(name, forKey: .name)
        try container.encode(url, forKey: .url)
    }
}

let decoder = JSONDecoder()
let data = """
{
    "status": true,
    "data": {
        "img_url": "/images/houses/",
        "houses": [
        {
        "id": "1",
        "name": "Kapital",
        "url": "https://kapital.com/",
        "img": "10fbf4bf6fd2928affb180.svg"
        }
        ]
    }
}
""".data(using: .utf8)!

let houses = try JSONDecoder().decode(ServerStatus.self, from: data).data.houses

print(houses)
like image 64
ielyamani Avatar answered Nov 10 '22 15:11

ielyamani