jsonswiftcodable

How to exclude properties from Swift Codable?


Swift's Encodable/Decodable protocols, released with Swift 4, make JSON (de)serialization quite pleasant. However, I have not yet found a way to have fine-grained control over which properties should be encoded and which should get decoded.

I have noticed that excluding the property from the accompanying CodingKeys enum excludes the property from the process altogether, but is there a way to have more fine-grained control?


Solution

  • The list of keys to encode/decode is controlled by a type called CodingKeys (note the s at the end). The compiler can synthesize this for you but can always override that.

    Let's say you want to exclude the property nickname from both encoding and decoding:

    struct Person: Codable {
        var firstName: String
        var lastName: String
        var nickname: String?
        
        private enum CodingKeys: String, CodingKey {
            case firstName, lastName
        }
    }
    

    If you want it to be asymmetric (i.e. encode but not decode or vice versa), you have to provide your own implementations of encode(with encoder: ) and init(from decoder: ):

    struct Person: Codable {
        var firstName: String
        var lastName: String
        
        // Since fullName is a computed property, it's excluded by default
        var fullName: String {
            return firstName + " " + lastName
        }
    
        private enum CodingKeys: String, CodingKey {
            case firstName, lastName, fullName
        }
    
        // We don't want to decode `fullName` from the JSON
        init(from decoder: Decoder) throws {
            let container = try decoder.container(keyedBy: CodingKeys.self)
            firstName = try container.decode(String.self, forKey: .firstName)
            lastName = try container.decode(String.self, forKey: .lastName)
        }
    
        // But we want to store `fullName` in the JSON anyhow
        func encode(to encoder: Encoder) throws {
            var container = encoder.container(keyedBy: CodingKeys.self)
            try container.encode(firstName, forKey: .firstName)
            try container.encode(lastName, forKey: .lastName)
            try container.encode(fullName, forKey: .fullName)
        }
    }