skip to Main Content

this is my API response from postman when "status" key value is open

{
    "data": {
        "id": 247,
        "status": "open",
}
        "code": 1,
        "message": "Details fetched successfully."
}

and this is API response from same API when "status" key value get changed to "completed"


{
    "data": {
        "id": 247,
         "status": “completed,
        "additional_data": {
            "id": 241,
            "booking_id": 247,
            "checklist_done": "{"4":"Gear Oil","2":"Engine Oil Change"}",
            "work_with_price": "{}",
            "work_price": "0",
            "status": "pending"
      },
    
    "code": 1,
    "message": "Details fetched successfully."
}

so if you look on above response a new key "additional_data" get added to response. what is the problem i am facing when "status" is "open" i am able to decode data but when "status" changed to "completed" i am not able to decode data

here what i had tried
this is structure which i have created to decode API response

struct ServicingModel: Codable {
    var data: DataClass?
    var code: Int?
    var message: String?
}


struct DataClass: Codable {
    var id: Int?
    var status: String?
    var additionalData: AdditionalData?

 enum CodingKeys: String, CodingKey {
        case id
        case status 
        case additionalData = "additional_data"
   }

init(from decoder: Decoder) throws {
            let values = try decoder.container(keyedBy: CodingKeys.self)
            id = try values.decodeIfPresent(Int.self, forKey: .id)
            status = try values.decodeIfPresent(String.self, forKey: .status)

            if let additionalDataOpt = try values.decodeIfPresent(AdditionalData.self,        forKey: .additionalData) {
                additionalData = additionalDataOpt
            } else {
                additionalData = nil
            }
}

}

struct AdditionalData: Codable {
    var id, bookingID: Int?
    var checklistDone: String?
    var workWithPrice: String?
    var workPrice: String?
    var status: String?

enum CodingKeys: String, CodingKey {
        case id
        case bookingID = "booking_id"
        case checklistDone = "checklist_done"
        case workWithPrice = "work_with_price"
        case workPrice = "work_price"
        case status
}
}

by using above structure i am able to decode data when status is open but when status is changed to completed i am unable to decode data, please guide me how i can create model to for additional data to map API response when additional_data key get added.

i got stuck on this problem from last three days any help would be appreciated . thanks for advance

2

Answers


  1. The JSON you shared is not a valid JSON, but this should work for you if i am getting the question right.

    // MARK: - MyModel
        struct MyModel: Codable {
            let data: DataClass?
            let code: Int?
            let message: String?
        }
        
        // MARK: - DataClass
        struct DataClass: Codable {
            let id: Int?
            let status: String?
            let additionalData: AdditionalData?
        
            enum CodingKeys: String, CodingKey {
                case id, status
                case additionalData = "additional_data"
            }
        }
        
        // MARK: - AdditionalData
        struct AdditionalData: Codable {
            let id, bookingID: Int?
            let checklistDone, workWithPrice, workPrice, status: String?
        
            enum CodingKeys: String, CodingKey {
                case id
                case bookingID = "booking_id"
                case checklistDone = "checklist_done"
                case workWithPrice = "work_with_price"
                case workPrice = "work_price"
                case status
            }
        }
    
    Login or Signup to reply.
  2. Notes:

    • As mentioned by others the JSON is invalid.
    • As you decode additionalData with decodeIfPresent, an if statement is not needed. If the key is missing decodeIfPresent returns nil.
    • Declare only those properties as optional whose key can be missing.
    • If you don’t need to encode the data conform only to Decodable.
    • If the properties won’t be modified, declare them as let constants.
    • A good practice is to decode status as enum.
    • You can get rid of the CodingKeys in AdditionalData and the conversion = "additional_data" by applying the convertFromSnakeCase key decoding strategy.

    struct ServicingModel: Decodable {
        var data: DataClass
        var code: Int
        var message: String
    }
    
    enum Status: String, Decodable {
        case open, completed
    }
    
    struct DataClass: Decodable {
        let id: Int
        let status: Status
        let additionalData: AdditionalData?
        
        enum CodingKeys: String, CodingKey {
            case id, status, additionalData
        }
        
        init(from decoder: Decoder) throws {
            let values = try decoder.container(keyedBy: CodingKeys.self)
            id = try values.decode(Int.self, forKey: .id)
            status = try values.decode(Status.self, forKey: .status)
            additionalData = try values.decodeIfPresent(AdditionalData.self, forKey: .additionalData)
        }
    }
    
    struct AdditionalData: Decodable {
        let id, bookingId: Int
        let checklistDone, workWithPrice, workPrice, status: String
    }
    

    let decoder = JSONDecoder()
    decoder.keyDecodingStrategy = .convertFromSnakeCase
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search