Search code examples
iosjsonswiftcodable

Deal with an API that changes format


Looking for a bit of advice. I'm tapping into WordsAPI to create a spellchecker iOS app using swift, however, depending on the words you search for the JSON response is sometimes in a different format.

Response for the word "test" looks like this (I've stripped out most of it just to get the point across)

{ 
    "word": "test", 
    "pronunciation": {
         "all": "tɛst"
    }
}

Whereas the response for the word "testing" looks like this

{ 
    "word": "testing", 
    "pronunciation": "'tɛstɪŋ" 
}

I'm using a model to decode the response data

struct WordDetails: Codable {
   let word: String
   let results: [Definition]
   let pronunciation: Pronounce
}

struct Pronounce: Codable {
   let all: String
}

struct Definition: Codable {
   let definition: String
   let partOfSpeech: String
   let synonyms: [String]?
}

But this will only deal with one scenario and fail to decode the other. Can I write it in such a way to deal with both formats?


Solution

  • You can implement the decoding yourself and try to decode pronunciation key as String type. If that fails with DecodingError.typeMismatch error you decode it as Pronounce type:

    struct WordDetails: Codable {
        let word: String
        let results: [Definition]
        let pronunciation: Pronounce
        
        enum CodingKeys: String, CodingKey {
            case word
            case results
            case pronunciation
        }
        
        init(from decoder: Decoder) throws {
            let container = try decoder.container(keyedBy: CodingKeys.self)
            word = try container.decode(String.self, forKey: .word)
            results = try container.decode([Definition].self, forKey: .results)
            do {
                let string = try container.decode(String.self, forKey: .pronunciation)
                pronunciation = Pronounce(all: string)
            } catch DecodingError.typeMismatch {
                pronunciation = try container.decode(Pronounce.self, forKey: .pronunciation)
            }
        }
    }