I have the following piece of code available here that decodes a JSON response from the Kitsu API (seriously just copy and paste in a playground environment and you should be good to go).
I am running into some decoding error that makes the code in the try
statement fail and I have no idea why.
I have two links that return the same JSON body (different results but same structure) except one fails and one doesn't.
// "https://kitsu.io/api/edge/anime?sort=popularityRank" <-- works
// "https://kitsu.io/api/edge/anime?sort=-startDate" <-- does not work
To help debug the one that fails I print out data
with the following statement:
print(String(data: data!, encoding: String.Encoding.utf8) as Any) // "as Any" to suppress warnings
And with this I am able to see the data object contains everything I need, so I'm ruling out a bad response (text was too large to copy so here's a screenshot, you'll get the picture):
If I had to guess, the issue is in the parsing, but the way I'm parsing it works for the first link. What exactly can I do to debug this? I've compared the json side by side and like I said, the structure between the responses is the same, only the content differs.
If you read the error closely, you'd find that it's quite descriptive. So, don't hide the error, like you did with print("error, wtf")
, and instead log/print it:
do {
let animeData = try JSONDecoder().decode(AnimeData.self, from: data!)
} catch {
print(error)
}
And the error would be:
valueNotFound(Swift.KeyedDecodingContainer<__lldb_expr_163.CoverImage.CodingKeys>, Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "data", intValue: nil), _JSONKey(stringValue: "Index 4", intValue: 4), CodingKeys(stringValue: "attributes", intValue: nil), CodingKeys(stringValue: "coverImage", intValue: nil)], debugDescription: "Cannot get keyed decoding container -- found null value instead.", underlyingError: nil))
I find it easier to read the error backwards, i.e. bottom up.
Right away, you see that the issue is "found null value instead" - i.e. your model didn't have an optional for something that was null.
Where? CodingKeys(stringValue: "coverImage", intValue: nil)]
- so, coverImage
is null.
Where is that? CodingKeys(stringValue: "attributes", intValue: nil)
- under attributes
, which you probably knew.
But which one, since it's a property of an array element? [CodingKeys(stringValue: "data", intValue: nil), _JSONKey(stringValue: "Index 4", intValue: 4)
- an element of data
index 4
, i.e. data[4]
, which is the fifth element.
Long story short, at least one (but actually two) of the Anime
objects' attribute
property has coverImage: null
in the "broken" response. To solve, make this property optional:
class Attributes: Codable {
// other properties
let coverImage: CoverImage?
}