在使用我正在使用的API的情况下,根据调用是否成功,一个API端点可以返回完全不同的响应。
如果成功,API端点将在根中返回一个请求的对象数组,如下所示:
[
{
"key1": "value1",
"key2": "value2",
"key3": "value3"
},
{
"key1": "value1",
"key2": "value2",
"key3": "value3"
},
...
]
我通常用try JSONDecoder().decode([Object].self, from: data)
解码
如果出现错误,API端点将返回完全不同的内容,如下所示:
{
"error": "value1",
"message": "value2",
"status": "value3"
}
,使用try JSONDecoder().decode([Object].self, from: data)
解码通常会失败。
现在,我的问题是,有没有一种方法可以对错误响应密钥进行解码,这种方式(我会说不是通常构建的API)没有创建一个名为Objects
的复数对象-该对象具有可选属性error
,message
,status
,例如{{ 1}}。
我的想法到了扩展数组objects
到某种程度上尝试解码where Element == Object
,error
,message
的地步,但是我遇到了status
。也许不可能那样做,所以任何其他甚至完全不同的建议都将受到欢迎。
答案 0 :(得分:1)
您可以尝试解码[Object],如果失败,请使用错误密钥解码另一个结构。
答案 1 :(得分:0)
引入“抽象”结构作为解码调用的接收者,并让该结构解码正确的类型并返回Result
对象
enum ApiErrorEnum: Error {
case error(ApiError)
}
struct ResponseHandler: Decodable {
let result: Result<[ApiResult], ApiErrorEnum>
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
do {
let values = try container.decode([ApiResult].self)
result = .success(values)
} catch {
let apiError = try container.decode(ApiError.self)
result = .failure(.error(apiError))
}
}
}
,然后可以将其用于例如闭包
func decodeApi(_ data: Data, completion: @escaping (Result<[ApiResult], ApiErrorEnum>?, Error?) -> ()) {
do {
let decoded = try JSONDecoder().decode(ResponseHandler.self, from: data)
completion(decoded.result, nil)
} catch {
completion(nil, error)
}
}
答案 2 :(得分:0)
利用do-catch块可以尝试解码一种类型,如果解码失败,则尝试另一种选择。我非常喜欢使用枚举来处理结果...
struct Opt1: Codable {
let key1, key2, key3: String
}
struct Opt2: Codable {
let error, message, status: String
}
enum Output {
case success([Opt1])
case failure(Opt2)
}
let decoder = JSONDecoder()
let data = json.data(using: .utf8)!
var output: Output
do {
let opt1Array = try decoder.decode([Opt1].self, from: data)
output = .success(opt1Array)
} catch {
let opt2 = try decoder.decode(Opt2.self, from: data)
output = .failure(opt2)
}
答案 3 :(得分:0)
我的建议是将JSON的根对象解码为具有关联类型的枚举
struct Item : Decodable {
let key1, key2, key3 : String
}
struct ResponseError : Decodable {
let error, message, status : String
}
enum Response : Decodable {
case success([Item]), failure(ResponseError)
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
do {
self = .success(try container.decode([Item].self))
} catch DecodingError.typeMismatch {
self = .failure(try container.decode(ResponseError.self))
}
}
}
并使用它
do {
let result = try JSONDecoder().decode(Response.self, from: data)
switch result {
case .success(let items): print(items)
case .failure(let error): print(error.message)
}
} catch {
print(error)
}
优良作法是仅捕获特定的.typeMismatch
错误,并将其他错误立即移交给调用方。