处理一个改变格式的 API

Deal with an API that changes format

正在寻求一些建议。 我正在利用 WordsAPI 使用 swift 创建一个拼写检查器 iOS 应用程序,但是,根据您搜索的单词,JSON 响应有时采用不同的格式。

对“测试”一词的响应如下所示(我删除了大部分内容只是为了说明问题)

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

而“测试”一词的响应如下所示

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

我正在使用一个模型来解码响应数据

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]?
}

但这只会处理一种情况而无法解码另一种情况。我可以这样写来处理两种格式吗?

您可以创建枚举并手动解码响应。

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

struct Pronounce: Codable {
   let all: String
}

enum PronounceResult: Decodable {
    case string(String)
    case object(Pronounce)

    public init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        if let string = try? container.decode(String.self) {
            self = .string(string)
            return
         }
         
         if let pronounce = try? container.decode(Pronounce.self) {
             self = .object(pronounce)
             return
         }
         let context = DecodingError.Context(codingPath: decoder.codingPath,
                                                    debugDescription: "Wrong type")
         throw DecodingError.typeMismatch(Value.self, context)
    }
}

你可以自己实现解码,尝试把读音键解码成String类型。如果失败并出现 DecodingError.typeMismatch 错误,您将其解码为 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)
        }
    }
}