Decode arrays where items can fail
Lets say we have a structure:
struct Participant: Codable {
let name: String
let startingTime: Date
}
and that we will fetch these participants from an endpoint, providing the following json:
[{
"name": "John",
"startingTime": 581167640.06502903
}, {
"name": "Mark",
"startingTime": 582031640.06502903
}, {
"name": "Tobias"
}]
We see that the third object in the JSON data, doesn't conform to Participant
since it does not have any valid startingTime
, so the question is now, how we will fetch all the valid participants?
Creating a failable wrapper
What we will have to do, is to make a failable wrapper, from where we can extract the participants if it was successfully created; and now we are at it, we will make it generic so it works for all kinds of Decodables
.
struct FailableDecodable<T: Decodable>: Decodable {
let value: T?
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
self.value = try? container.decode(T.self)
}
}
The magic happens in the custom decoding initializer, where we try to decode something of the type T
and saves it into value
. If this fails, the value
will be nil
, why we on a sequence of FailableDecodable
can use .compactMap
to strip out all nil
's and map over the value
; why we now safely can decode all the objects in the json that conforms to our model:
let decoder = JSONDecoder()
let wrapped = try! decoder.decode([FailableDecodable<Participant>].self, from: data)
let participants = wrapped.compactMap { $0.value }
To see a fully working example, see this gist