Search code examples
swiftcodablejsondecoderjsonencoder

Exclude CodingKeys that doesn't need to be altered?


Say I have a struct User model which has many properties in it.

struct User: Codable {
    let firstName: String
    let lastName: String
    // many more properties...
}

As you can see above it conforms to Codable. Imagine if the lastName property is should be encoded/decoded as secondName and I would like to keep it as lastName at my end, I need to add the CodingKeys to the User model.

struct User: Codable {
    //...
    private enum CodingKeys: String, CodingKey {
        case firstName
        case lastName = "secondName"
        // all the other cases...
    }
}

Is there any possible way to avoid including all the cases in CodingKeys that have the same value as rawValue like the firstName in the above example (Feels redundant)? I know if I avoid the cases in CodingKeys it won't be included while decoding/encoding. But, is there a way I could override this behaviour?


Solution

  • There is a codable way, but the benefit is questionable.

    Create a generic CodingKey

    struct AnyKey: CodingKey {
        var stringValue: String
        var intValue: Int?
    
        init?(stringValue: String) { self.stringValue = stringValue; self.intValue = nil }
        init?(intValue: Int) { self.stringValue = String(intValue); self.intValue = intValue }
    }
    

    and add a custom keyDecodingStrategy

    struct User: Codable {
        let firstName: String
        let lastName: String
        let age : Int
    }
    
    let jsonString = """
    {"firstName":"John", "secondName":"Doe", "age": 30}
    """
    
    let data = Data(jsonString.utf8)
    
    do {
        let decoder = JSONDecoder()
        decoder.keyDecodingStrategy = .custom({ keyPath -> CodingKey in
            let key = keyPath.last!
            return key.stringValue == "secondName" ? AnyKey(stringValue:"lastName")! : key
        })
        let result = try decoder.decode(User.self, from: data)
        print(result)
    } catch {
        print(error)
    }