Codable and mismatched keys

Networking Mid-level Swift 5.0+ iOS 15+ Reviewed By Alok Singh

Predict the output

What happens when this decodes?

struct User: Decodable {
    let userName: String
    enum CodingKeys: String, CodingKey { case userName = "user_name" }
}
let json = #"{"user_name": "ana"}"#.data(using: .utf8)!
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let user = try decoder.decode(User.self, from: json)
Options
Hint 1 of 1

Which runs first: the key strategy or the CodingKeys match?

Choose an answer, then open Show answer below to check it.

Show answer

Answer: B It throws keyNotFound

Correct. Use either the strategy or the custom CodingKeys, not both.

Why not the others?
  • A It decodes "ana". The strategy has already renamed the key to userName, which doesn't match "user_name".
  • C userName becomes an empty string. Decoding never invents default values.
  • D It doesn't compile. The code compiles; the failure happens at runtime.

30-second answer

Codable is Encodable plus Decodable; the compiler generates the conversion for types whose properties are all Codable. For different key names, either set keyDecodingStrategy = .convertFromSnakeCase or declare a CodingKeys enum with custom raw values. Don't combine both for the same key: the strategy converts JSON keys first, so a raw value like "user_name" no longer matches.

Practise saying it · 30 s. No recording, just a timer

Explain Codable and custom keys.

Say your answer out loud, then check which of these points you covered:

  • Compiler-generated conformance
  • CodingKeys or key strategy
  • Don't mix them

Deep dive

Custom init(from:) handles nested or inconsistent JSON.

Optional properties decode missing keys as nil; non-optionals throw keyNotFound.

Use decodeIfPresent with a default for lenient decoding.

Read DecodingError's codingPath to see exactly what failed.

Common mistakes

  • Mixing convertFromSnakeCase with snake_case CodingKeys.
  • Swallowing DecodingError details.

Senior take & follow-ups

Seniors know the strategy-versus-CodingKeys trap and read codingPath when debugging.

Follow-up questions

Think of your answer first, then open the hint.

  1. How do you decode a property that may be missing?

    Show hint

    Make it optional, or decodeIfPresent with a default.

  2. How do you flatten nested JSON?

    Show hint

    nestedContainer(keyedBy:forKey:) in init(from:).

Suggest a fix if something here is wrong or out of date.