Reputation: 1318
I'm currently working with a bad designed JSON Api... This returns always a value (eg. String, Int, Double...) or false(not null).
What is the best way to handle this with decodable, as Any is not supported by Codable?
A key can look like this:
{
"key": "Test",
}
Or like this(I know, should be null instead of false):
{
"key": false,
}
And this is not possible:
struct Object: Decodable {
let key: Any?
}
Upvotes: 0
Views: 1762
Reputation: 16436
I have same situation where ID can be Int or String
class MyClass: Codable {
let id: Int?
required init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
do {
let stringId = try values.decodeIfPresent(String.self, forKey: .id)
id = Int(stringId ?? "0")
} catch {
id = try values.decodeIfPresent(Int.self, forKey: .id)
}
}
}
Inside required init(from decoder: Decoder) throws
I have another do try block in which I convert it
Upvotes: 0
Reputation: 54706
You can create a generic wrapper type which assign nil
to an Optional
value if the value for a key is false
, otherwise it decodes the value. Then instead of storing the actual types, you can wrap them in this wrapper.
struct ValueOrFalse<T:Decodable>: Decodable {
let value:T?
public init(from decoder:Decoder) throws {
let container = try decoder.singleValueContainer()
let falseValue = try? container.decode(Bool.self)
if falseValue == nil {
value = try container.decode(T.self)
} else {
value = nil
}
}
}
struct RandomJSONStruct: Decodable {
let anInt:ValueOrFalse<Int>
let aString:ValueOrFalse<String>
}
let noValueJson = """
{
"anInt": false,
"aString": "Test"
}
"""
do {
print(try JSONDecoder().decode(RandomJSONStruct.self, from: noValueJson.data(using: .utf8)!))
} catch {
print(error)
}
Upvotes: 2