I try to use Swift 4.1's new feature to convert snake-case to camelCase during JSON decoding.
Here is the example:
struct StudentInfo: Decodable {
internal let studentID: String
internal let name: String
internal let testScore: String
private enum CodingKeys: String, CodingKey {
case studentID = "student_id"
case name
case testScore
}
}
let jsonString = """
{"student_id":"123","name":"Apple Bay Street","test_score":"94608"}
"""
do {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let decoded = try decoder.decode(StudentInfo.self, from: Data(jsonString.utf8))
print(decoded)
} catch {
print(error)
}
I need provide custom CodingKeys
since the convertFromSnakeCase
strategy can't infer capitalization for acronyms or initialisms (such as studentID
) but I expect the convertFromSnakeCase
strategy will still work for testScore
. However, the decoder throws error ("No value associated with key CodingKeys") and it seems that I can't use convertFromSnakeCase
strategy and custom CodingKeys
at the same time. Am I missing something?
The key strategies for JSONDecoder
(and JSONEncoder
) are applied to all keys in the payload – including those that you provide a custom coding key for. When decoding, the JSON key will first be mapped using the given key strategy, and then the decoder will consult the CodingKeys
for the given type being decoded.
In your case, the student_id
key in your JSON will be mapped to studentId
by .convertFromSnakeCase
. The exact algorithm for the transformation is given in the documentation:
Capitalize each word that follows an underscore.
Remove all underscores that aren't at the very start or end of the string.
Combine the words into a single string.
The following examples show the result of applying this strategy:
fee_fi_fo_fum
Converts to:
feeFiFoFum
feeFiFoFum
Converts to:
feeFiFoFum
base_uri
Converts to:
baseUri
You therefore need to update your CodingKeys
to match this:
internal struct StudentInfo: Decodable, Equatable {
internal let studentID: String
internal let name: String
internal let testScore: String
private enum CodingKeys: String, CodingKey {
case studentID = "studentId"
case name
case testScore
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With