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!

18 Likes

Finally finished 2.0!

Along with CocoaPods support, The major goal for this release was to reduce API surface level by unifying Property variation, make the abstractions more meaningful, and add a couple useful wrappers.

5 Likes

3.0 has been released with CodingKey customization using Macros! GitHub - GottaGetSwifty/CodableWrappers: A Collection of PropertyWrappers to make custom Serialization of Swift Codable Types easy