create custom decoding strategy that converts snake to camel case and capitalizes the word "id" in swift

One way to create a custom decoding strategy in Swift that converts snake_case to camelCase and capitalizes the word id is by creating a struct that conforms to the CodingKey protocol and implementing the init and stringValue methods. Here's an example implementation:

main.swift
struct SnakeToCamelCaseCodingKey: CodingKey {
    var stringValue: String
    var intValue: Int?

    init?(stringValue: String) {
        self.stringValue = SnakeToCamelCaseCodingKey.convertSnakeToCamelCase(stringValue)
    }

    init?(intValue: Int) {
        self.stringValue = "\(intValue)"
        self.intValue = intValue
    }

    // Convert snake_case to camelCase and capitalize the word "id"
    static func convertSnakeToCamelCase(_ key: String) -> String {
        var result = ""
        var capitalizeNext = false
        for character in key {
            if character == "_" {
                capitalizeNext = true
            } else if capitalizeNext || result.isEmpty {
                result.append(character.uppercased())
                capitalizeNext = false
            } else {
                result.append(character)
            }
        }
        if let range = result.range(of: "Id$") {
            result.replaceSubrange(range, with: "ID")
        }
        return result
    }
}
1012 chars
34 lines

To use this custom decoding strategy, you need to create a JSONDecoder instance and set its keyDecodingStrategy property to .custom with a closure that returns the SnakeToCamelCaseCodingKey for each key:

main.swift
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .custom { keys in
    var lastKey = keys.last!
    for key in keys.dropLast().reversed() {
        lastKey = SnakeToCamelCaseCodingKey(stringValue: key.stringValue)!
        lastKey = SnakeToCamelCaseCodingKey(stringValue: lastKey.stringValue + lastKey.stringValue) ?? lastKey
    }
    return lastKey
}
362 chars
10 lines

Now, when you decode a JSON object with this JSONDecoder instance, all keys in snake_case will be automatically converted to camelCase and the word id will be capitalized:

main.swift
struct Person: Codable {
    let firstName: String
    let lastName: String
    let userId: Int
}

let jsonString = """
{
    "first_name": "John",
    "last_name": "Doe",
    "user_id": 123
}
"""

let jsonData = jsonString.data(using: .utf8)!
let person = try! decoder.decode(Person.self, from: jsonData)
print(person) // prints: Person(firstName: "John", lastName: "Doe", userId: 123)
387 chars
18 lines

Note: This implementation assumes that all keys in the JSON object are in snake_case. If you also need to support keys in camelCase or other formats, you will need to modify the convertSnakeToCamelCase method accordingly.

gistlibby LogSnag