-1

I'm currently learning swift and i'm trying to make a api call that can send two different responses:

First one is:

{
    "data": {
        "id": 1
},
    "error": null
}

Second one is:

{
    "data": null,
    "error": " Password not matching"
}

So in the first json the data is a nested container, and in the second one its not.

What i have so far is the following, which works fine for the first case, but i have no idea how to change my struct to handle the second case. Any hits/ideas would be greatly appreciated:

struct ApiData {
    let userID: Int?
    let error: String?
}

extension ApiData: Decodable{

    enum CodingKeys: String, CodingKey {
        case data = "data"
        case userId = "id"
        case error = "error"
    }

    init(from decoder: Decoder) throws {

        let container = try decoder.container(keyedBy: CodingKeys.self)
        do {
            let data = try container.nestedContainer(keyedBy: CodingKeys.self, forKey: .data)
            let userId = try data.decode(Int.self, forKey: .userId)
            self.init(userID: nil, error: nil)
        } catch let error {
            print(error)
            throw error
        }
    }
}

If i try in the do block to decode the error case, when received the first type of response, will get a "Data is not in the correct format error" thrown.

Hilalkah
  • 945
  • 15
  • 37
CodeGeass
  • 619
  • 2
  • 7
  • 20

1 Answers1

1

data is object which can be nil. You're missing optional property for data and userId (id) should be property of data.

struct ApiData: Decodable {
    let data: DataObject?
    let error: String?
}

Also you don't have struct for data

struct DataObject: Decodable {
    let userId: Int

    enum CodingKeys: String, CodingKey {
        case userId = "id"
    }
}

Notes: you don't have to use CodingKeys for ApiData, just for DataObject

Robert Dresler
  • 10,580
  • 2
  • 22
  • 40
  • Thank you, this worked and got me a better picture of how to use Decodable. I don't understand what you mean by that note though. What should i change to a variable? I've currently reworked it like this: extension DataObject{ init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) let userId = try container.decode(Int.self, forKey: .userId) self.init(userId: userId) } } – CodeGeass Dec 12 '18 at 14:39
  • @CodeGeass yes, you're right, you don't have to use it. – Robert Dresler Dec 12 '18 at 14:41
  • @CodeGeass but look, when you're using `CodingKeys`, you don't have to have init with decoder. All you need are just `CodingKeys` – Robert Dresler Dec 12 '18 at 14:43
  • @Sh_Khan but better would be if he had same struct format as his JSON. – Robert Dresler Dec 12 '18 at 14:46