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 (_ type: T.Type, from data: Data) throws -> T where T: Decodable showcases 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.
Liulishuo Tech Team
Help everyone become a global citizen!
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.