Announcing CodableWrappers

Hello!

I'd like to announce version 1.0.0 of a library I'm calling CodableWrappers.

It uses Property Wrappers to greatly simplify non-default serialization of Codable Types. Check out the Readme or blog post for more information, but I'll give a quick overview here as well.

The basic idea is to move custom encoding/decoding to Property Wrappers. So e.g. if you have a basic Book:

struct Book: Codable {
    /// Encodes with secondsSince1970
    let published: Date
    let uuid: String
    let title: String
    let author: String
}

Rather than customizing every encoder/decoder you use

let jsonEncoder = JSONEncoder()
jsonEncoder.dateEncodingStrategy = .secondsSince1970

let jsonDecoder = JSONDecoder()
jsonDecoder.dateDecodingStrategy = .secondsSince1970

Or customizing the Codable implementation

struct Book: Codable {
    let count: Int
    let title: String
    let author: String
    /// Seconds Since 1970
    let released: Date

    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        self.count = try values.decode(Int.self, forKey: .count)
        self.title = try values.decode(Int.self, forKey: .title)
        self.author = try values.decode(Int.self, forKey: .author)
        let secondsSince = values.decode(Double.self, forKey: .released)
        self.released = Date(timeIntervalSince1970: secondsSince)
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(count, forKey: .count)
        try container.encode(title, forKey: .title)
        try container.encode(author, forKey: .author)
        try container.encode(released.timerIntervalSince1970, forKey: .released)
    }
}

You can simply add a Property Wrapper

struct Book: Codable {
    @SecondsSince1970DateCoding
    var published: Date
    let uuid: String
    let title: String
    let author: String
}

The need for this is especially clear if you have a data structure that uses more than one kind of encoding

struct Catalog: Codable {
    @MillisecondsSince1970DateCoding
    var updatedAt: Date
    let books: [Book]
}

struct Book: Codable {
    @SecondsSince1970DateCoding
    var published: Date
    let uuid: String
    let title: String
    let author: String
}

This approach has several advantages compared to the status quo:

  • Declarative
  • Extendable
  • Declare once for all Encoders and Decoders. (e.g. JSONEncoder and PropertyListEncoder)
  • Can customize (de/en)coding without overriding encode(to: Encoder) or init(with decoder)
  • Multiple (de/en)coding strategies within a data structure
  • Fully Cross Platform

The library currently includes analogs for the customizations available in JSON(En/De)Coder as well as ways to easily write your own.

Feedback and ideas for additional features are welcome!

13 Likes
Terms of Service

Privacy Policy

Cookie Policy