Swift codable: an object that is come from an API, changed from type Array to Object

An API changed its JSON, a field named contactMedium, that was coming in form of a Array changed to an Object:

was like this :

{

"contactMedium": [

        {

            "type": "EMAIL",

            "characteristic": {

                "emailAddress": "ibenedit"

            }

        }

    ],

}

become like this :

{

"contactMedium": {

        "characteristics": {

            "emailAddress": "ibeneditobr"

        },

        "type": "EMAIL"

    },

}

My question is, how I implement the init's struct ("init(from decoder: Decoder) throws {") , to convert from object to Array ?

In my struct I tried to change:

from : public var contactMedium: [ContactMedium]?

to : public var contactMedium: ContactMedium?

But app crashes in various places, because of use the array's methods like filter.

Answered by Ptit-Xav in 738282022

This is quite ugly but to can help you. The new structure read the new JSON but return the previous interface `// Old structure

struct ContactMediumOld: Codable {

    struct ContactMedium: Codable {

        var type: String

        struct Characteristic: Codable {

            var emailAddress : String

        }

        var characteristic: Characteristic

    }

    var contactMedium: [ContactMedium]

}

// New structure

struct ContactMediumNew: Codable {

    struct ContactMedium: Codable {

        var type: String

        struct Characteristic: Codable {

            var emailAddress : String

        }

        // name of property also changed so use a computed for old name

        private var characteristics: Characteristic

        var characteristic: Characteristic {

            characteristics

        }

    }

    

    // read an simple object

    private var contactMediumNew: ContactMedium

    

    enum CodingKeys: String, CodingKey {

        case contactMediumNew = "contactMedium"

    }

    // but return an array

    var contactMedium: [ContactMedium] {

        [contactMediumNew]

    }

}`

I would suggest you change your code to not use an array now the API has changed. Trying to keep this code will make your app more difficult to maintain. BTW you could create a dummy private var that has a codingKey with this property and set the contactMedium to be an computed array var returning the object.

Accepted Answer

This is quite ugly but to can help you. The new structure read the new JSON but return the previous interface `// Old structure

struct ContactMediumOld: Codable {

    struct ContactMedium: Codable {

        var type: String

        struct Characteristic: Codable {

            var emailAddress : String

        }

        var characteristic: Characteristic

    }

    var contactMedium: [ContactMedium]

}

// New structure

struct ContactMediumNew: Codable {

    struct ContactMedium: Codable {

        var type: String

        struct Characteristic: Codable {

            var emailAddress : String

        }

        // name of property also changed so use a computed for old name

        private var characteristics: Characteristic

        var characteristic: Characteristic {

            characteristics

        }

    }

    

    // read an simple object

    private var contactMediumNew: ContactMedium

    

    enum CodingKeys: String, CodingKey {

        case contactMediumNew = "contactMedium"

    }

    // but return an array

    var contactMedium: [ContactMedium] {

        [contactMediumNew]

    }

}`

Swift codable: an object that is come from an API, changed from type Array to Object
 
 
Q