Home > OS >  Swift Encodable: encode nil as an empty object
Swift Encodable: encode nil as an empty object

Time:09-28

How can I encode a nil property as an empty JSON object?

struct Foo: Encodable {
    let id = 10
    let bar: Bar? = nil
}

struct Bar: Encodable {
    let number: Int
}

let data = try! JSONEncoder().encode(Foo())

print(String(data: data, encoding: .utf8)!)

This prints out:

"{"id":7}"

What I want is:

"{"id":7, "bar":{}}"

CodePudding user response:

You can introduce an empty struct with no properties to the encoder, when bar = nil

struct Foo: Encodable {
    let id = 10
    let bar: Bar? = nil
    
    enum CodingKeys : String, CodingKey {
        case id
        case bar
    }
    
    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(id, forKey: .id)
        
        if let bar = bar {
            try container.encode(bar, forKey: .bar)
        }
        else {
            try container.encode(Empty(), forKey: .bar)
        }
    }
}

struct Bar: Encodable {
    let number: Int
}

struct Empty: Encodable {
}

CodePudding user response:

Implement a custom encode(to:) for Foo and use an empty dictionary if Bar is nil

struct Foo: Encodable {
    let id = 10
    let bar: Bar? = nil

    enum CodingKeys: String, CodingKey {
        case id, bar
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(id, forKey: .id)
        switch bar {
        case .some(let value):
            try container.encode(value, forKey: .bar)
        case .none:
            try container.encode([String: Bar?](), forKey: .bar)
        }
    }
}
  • Related