Using Swift 4.1 JSONEncoder/JSONDecoder KeyEncodingStrategy to Bridge Snake_case and CamelCase and Create Custom Key Strategies
This article explains how Swift 4.0 introduced Codable, how Swift 4.1 added keyEncodingStrategy and keyDecodingStrategy to automatically convert between snake_case and camelCase, and how to implement custom key transformations such as PascalCase using the .custom strategy.
Swift 4.0 added the Codable protocol, which combines Encodable and Decodable, allowing the compiler to synthesize init(from: Decoder) and encode(to: Encoder). Swift 4.1 introduced two new properties on JSONEncoder and JSONDecoder: keyEncodingStrategy and keyDecodingStrategy.
1. Bridging Snake_case and CamelCase
When a JSON payload uses snake_case keys but a Swift struct uses camelCase property names, decoding and encoding fail unless a custom CodingKeys enum is provided.
let jsonStr = """
{
"age": 18,
"first_name": "Leon"
}
"""
struct Person: Codable {
var age: Int
var firstName: String
}In Swift 4.0 you would define:
enum CodingKeys: String, CodingKey {
case age
case firstName = "first_name"
}Swift 4.1 simplifies this with built‑in strategies:
// Encoding
let leon = Person(age: 18, firstName: "Leon")
let encoder = JSONEncoder()
encoder.keyEncodingStrategy = .convertToSnakeCase
let resultData = try? encoder.encode(leon)
// Decoding
let data = jsonStr.data(using: .utf8)!
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let person = try? decoder.decode(Person.self, from: data)2. Custom Key Strategies
For other naming conventions, such as PascalCase, you can use the .custom case of the strategy, which receives a closure ([CodingKey]) -> CodingKey. The closure gets the full path of coding keys, typically using the last element.
struct SimpleCodingKey: CodingKey {
var stringValue: String
var intValue: Int?
init(stringValue: String) { self.stringValue = stringValue }
init(intValue: Int) {
self.stringValue = "\(intValue)"
self.intValue = intValue
}
}
extension JSONEncoder.KeyEncodingStrategy {
static var convertToPascalCase: JSONEncoder.KeyEncodingStrategy {
return .custom { codingKeys in
let str = codingKeys.last!.stringValue
guard let firstChar = str.first else { return SimpleCodingKey(stringValue: str) }
let s = str.prefix(1).capitalized + str.dropFirst()
return SimpleCodingKey(stringValue: s)
}
}
}
let encoder = JSONEncoder()
encoder.keyEncodingStrategy = .convertToPascalCase
let resultData = try? encoder.encode(leon)Note that SimpleCodingKey 's initializer is non‑failable, yet it satisfies the protocol’s failable initializer requirement. The extension adds a static variable that can be used like an enum case.
Decoding can be handled similarly by providing a counterpart that lower‑cases the first character.
3. Design Highlights
Interface‑based OOP: The CodingKey protocol abstracts key handling, enabling the addition of custom strategies without changing the encoder/decoder core. The overall design of Encoder, Decoder, and Codable is based on protocols, making it format‑agnostic.
Associated‑value enums for configuration: The KeyEncodingStrategy and KeyDecodingStrategy enums use associated values (e.g., .custom(([CodingKey]) -> CodingKey)) to allow elegant, runtime‑configurable behavior, similar to other strategies like dateEncodingStrategy.
Generics and metatype programming: Decoding is performed with try decoder.decode(Person.self, from: data), where Person.self is a metatype. The generic signature
func decode<T>(_ type: T.Type, from data: Data) throws -> T where T: Decodableshowcases Swift’s powerful generic and metatype capabilities.
Conclusion
Codable, introduced in Swift 4.0 and enhanced in Swift 4.1, provides a first‑class, compiler‑synthesized serialization solution for Swift. Its design offers interface‑driven extensibility, elegant strategy configuration via associated‑value enums, and leverages generics and metatypes, making it a top choice for Swift developers building mobile applications.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
