NinjaDeveloper
NinjaDeveloper

Reputation: 1712

ignore the following properties in swift Codable?

I have this Account struct. I want to ignore the following properties environments and Id in encoding to JSON object when I send "POST" endpoint and use them return success decoding to swift object

update I have this error Property type '[Environment]' does not match that of the 'wrappedValue' property of its wrapper type 'SkipEncode'

struct Account: Codable {
    let accountID, displayName, managedByID, id: String
    let environments: [Environment]
    let contacts: [Contact]

    enum CodingKeys: String, CodingKey {
        case accountID
        case displayName
        case managedID
        case id
        case environments
        case contacts
    }
}

Upvotes: 1

Views: 4531

Answers (3)

New Dev
New Dev

Reputation: 49590

Another approach, if you don't want to manually implement encode(to:) and give up on the benefits of Codable auto synthesis, you could create a property wrapper as a way of marking the properties you want to skip:

@propertyWrapper
struct SkipEncode<T> {
   var wrappedValue: T
}

extension SkipEncode: Decodable where T: Decodable {
   init(from decoder: Decoder) throws {
      let container = try decoder.singleValueContainer()
      self.wrappedValue = try container.decode(T.self)
   }
}

extension SkipEncode: Encodable {
   func encode(to encoder: Encoder) throws {
      // nothing to do here
   }
}

extension KeyedEncodingContainer {
   mutating func encode<T>(_ value: SkipEncode<T>, forKey key: K) throws {
      // overload, but do nothing
   }
}

Then you could just use @SkipEncode like so:

struct Account: Codable {
    let accountID, displayName, managedByID: String
    let contacts: [Contact]
    
    @SkipEncode
    let id: String

    @SkipEncode 
    let environments: [Environment]
}

Upvotes: 9

Leo Dabus
Leo Dabus

Reputation: 236360

Follow up in the approach suggested by NewDev. If you want to implement a property wrapper you would need to implement a generic one to be able to skip any property, not only strings:

@propertyWrapper
struct SkipEncode<T: Decodable> {
   var wrappedValue: T
}

extension SkipEncode: Codable {
    init(from decoder: Decoder) throws {
       wrappedValue = try decoder.singleValueContainer().decode(T.self)
    }
    func encode(to encoder: Encoder) throws { }
}

extension KeyedEncodingContainer {
    mutating func encode<T>(_ value: SkipEncode<T>, forKey key: K) throws { }
}

Playground testing:

struct Environment: Codable { } struct Contact: Codable { }

struct Account: Codable {
    let accountID, displayName, managedByID: String

    @SkipEncode
    var id: String

    @SkipEncode
    var environments: [Environment]
    
    let contacts: [Contact]
}

let account = Account.init(accountID: "account", displayName: "name", managedByID: "manager", id: "id", environments: [], contacts: [])
let dt = try JSONEncoder().encode(account)
print(String.init(data: dt, encoding: .utf8)!) // {"accountID":"account","contacts":[],"managedByID":"manager","displayName":"name"}

Upvotes: 2

Eric Hua
Eric Hua

Reputation: 1015

If you want to ignore, for example environments when encoding, you can define your own encoding implementation:

struct Account: Codable {
    let accountID, displayName, managedByID, id: String
    let environments: [Environment]
    let contacts: [Contact]

    enum CodingKeys: String, CodingKey {
        case accountID, displayName, managedByID, id, environments, contacts
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(accountID, forKey: .accountID)
        try container.encode(displayName, forKey: .displayName)
        // ... just don't include the environments here
    }
}

Upvotes: 5

Related Questions