Search code examples
iosswiftfoundationjsondecoder

JSONDecoder fails to find key that is present


When attempting to parse the response from the Create Team call in Github's REST api, JSONDecoder fails when parsing many of the snake cased keys for a Repository. When decoding through JSONSerialization, it is able to find all keys without problem.

For example, when running in Playground in Xcode 11.0 (11A420a), the decoding fails when decoding with JSONDecoder.

import Foundation

let jsonData = """
{
"id": 12345,
"name": "swift",
"ssh_url": "[email protected]:apple/swift.git"
}
""".data(using: .utf8)!

struct ExampleModel: Codable {
    let id: Int
    let name: String
    let sshURL: String
}

let jsonObject = try! JSONSerialization.jsonObject(with: jsonData, options: []) as! [String: Any]
print("JSONSerialization:", jsonObject["id"]!, jsonObject["name"]!, jsonObject["ssh_url"]!)

let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let decodedObject = try! decoder.decode(ExampleModel.self, from: jsonData) // Fails here
print("JSONDecoder:", decodedObject.id, decodedObject.name, decodedObject.sshURL)

// Output:
//
// JSONSerialization: 12345 swift [email protected]:apple/swift.git
// Fatal error: 'try!' expression unexpectedly raised an error: Swift.DecodingError.keyNotFound(CodingKeys(stringValue: "sshURL", intValue: nil), Swift.DecodingError.Context(codingPath: [], debugDescription: "No value associated with key CodingKeys(stringValue: \"sshURL\", intValue: nil) (\"sshURL\"), converted to ssh_url.", underlyingError: nil)): file MyPlayground.playground, line 22

Is there something different that I should be doing to parse this value?

Swift version:

Apple Swift version 5.1 (swiftlang-1100.0.270.13 clang-1100.0.33.7)
Target: x86_64-apple-darwin19.0.0

Solution

  • Try changing sshURL to sshUrl. The keyDecodingStartegy will transform sshURL into ssh_URL, which doesn't match your key. sshUrl will be transformed into ssh_url, which will match your key.