Code Monkey home page Code Monkey logo

bettercodable's Introduction

Better Codable through Property Wrappers

Level up your Codable structs through property wrappers. The goal of these property wrappers is to avoid implementing a custom init(from decoder: Decoder) throws and suffer through boilerplate.

@LossyArray

@LossyArray decodes Arrays and filters invalid values if the Decoder is unable to decode the value. This is useful when the Array contains non-optional types and your API serves elements that are either null or fail to decode within the container.

Usage

Easily filter nulls from primitive containers

struct Response: Codable {
    @LossyArray var values: [Int]
}

let json = #"{ "values": [1, 2, null, 4, 5, null] }"#.data(using: .utf8)!
let result = try JSONDecoder().decode(Response.self, from: json)

print(result) // [1, 2, 4, 5]

Or silently exclude failable entities

struct Failable: Codable {
    let value: String
}

struct Response: Codable {
    @LossyArray var values: [Failable]
}

let json = #"{ "values": [{"value": 4}, {"value": "fish"}] }"#.data(using: .utf8)!
let result = try JSONDecoder().decode(Response.self, from: json)

print(result) // [Failable(value: "fish")]

@LossyDictionary

@LossyDictionary decodes Dictionaries and filters invalid key-value pairs if the Decoder is unable to decode the value. This is useful if the Dictionary is intended to contain non-optional values and your API serves values that are either null or fail to decode within the container.

Usage

Easily filter nulls from primitive containers

struct Response: Codable {
    @LossyDictionary var values: [String: String]
}

let json = #"{ "values": {"a": "A", "b": "B", "c": null } }"#.data(using: .utf8)!
let result = try JSONDecoder().decode(Response.self, from: json)

print(result) // ["a": "A", "b": "B"]

Or silently exclude failable entities

struct Failable: Codable {
    let value: String
}

struct Response: Codable {
    @LossyDictionary var values: [String: Failable]
}

let json = #"{ "values": {"a": {"value": "A"}, "b": {"value": 2}} }"#.data(using: .utf8)!
let result = try JSONDecoder().decode(Response.self, from: json)

print(result) // ["a": "A"]

@DefaultCodable

@DefaultCodable provides a generic property wrapper that allows for default values using a custom DefaultCodableStrategy. This allows one to implement their own default behavior for missing data and get the property wrapper behavior for free. Below are a few common default strategies, but they also serve as a template to implement a custom property wrapper to suit your specific use case.

While not provided in the source code, it's a sinch to create your own default strategy for your custom data flow.

struct RefreshDaily: DefaultCodableStrategy {
    static var defaultValue: CacheInterval { return CacheInterval.daily }
}

struct Cache: Codable {
    @DefaultCodable<RefreshDaily> var refreshInterval: CacheInterval
}

let json = #"{ "refreshInterval": null }"#.data(using: .utf8)!
let result = try JSONDecoder().decode(Cache.self, from: json)

print(result) // Cache(refreshInterval: .daily)

@DefaultFalse

Optional Bools are weird. A type that once meant true or false, now has three possible states: .some(true), .some(false), or .none. And the .none condition could indicate truthiness if BadDecisions™ were made.

@DefaultFalse mitigates the confusion by defaulting decoded Bools to false if the Decoder is unable to decode the value, either when null is encountered or some unexpected type.

Usage

struct UserPrivilege: Codable {
    @DefaultFalse var isAdmin: Bool
}

let json = #"{ "isAdmin": null }"#.data(using: .utf8)!
let result = try JSONDecoder().decode(Response.self, from: json)

print(result) // UserPrivilege(isAdmin: false)

@DefaultEmptyArray

The weirdness of Optional Booleans extends to other types, such as Arrays. Soroush has a great blog post explaining why you may want to avoid Optional Arrays. Unfortunately, this idea doesn't come for free in Swift out of the box. Being forced to implement a custom initializer in order to nil coalesce nil arrays to empty arrays is no fun.

@DefaultEmptyArray decodes Arrays and returns an empty array instead of nil if the Decoder is unable to decode the container.

Usage

struct Response: Codable {
    @DefaultEmptyArray var favorites: [Favorite]
}

let json = #"{ "favorites": null }"#.data(using: .utf8)!
let result = try JSONDecoder().decode(Response.self, from: json)

print(result) // Response(favorites: [])

@DefaultEmptyDictionary

As mentioned previously, Optional Dictionaries are yet another container where nil and emptiness collide.

@DefaultEmptyDictionary decodes Dictionaries and returns an empty dictionary instead of nil if the Decoder is unable to decode the container.

Usage

struct Response: Codable {
    @DefaultEmptyDictionary var scores: [String: Int]
}

let json = #"{ "scores": null }"#.data(using: .utf8)!
let result = try JSONDecoder().decode(Response.self, from: json)

print(result) // Response(values: [:])

@LosslessValue

All credit for this goes to Ian Keen.

Somtimes APIs can be unpredictable. They may treat some form of Identifiers or SKUs as Ints for one response and Strings for another. Or you might find yourself encountering "true" when you expect a boolean. This is where @LosslessValue comes into play.

@LosslessValue will attempt to decode a value into the type that you expect, preserving the data that would otherwise throw an exception or be lost altogether.

Usage

struct Response: Codable {
    @LosslessValue var sku: String
    @LosslessValue var isAvailable: Bool
}

let json = #"{ "sku": 12345, "isAvailable": "true" }"#.data(using: .utf8)!
let result = try JSONDecoder().decode(Response.self, from: json)

print(result) // Response(sku: "12355", isAvailable: true)

Date Wrappers

One common frustration with Codable is decoding entities that have mixed date formats. JSONDecoder comes built in with a handy dateDecodingStrategy property, but that uses the same date format for all dates that it will decode. And often, JSONDecoder lives elsewhere from the entity forcing tight coupling with the entities if you choose to use its date decoding strategy.

Property wrappers are a nice solution to the aforementioned issues. It allows tight binding of the date formatting strategy directly with the property of the entity, and allows the JSONDecoder to remain decoupled from the entities it decodes. The @DateValue wrapper is generic across a custom DateValueCodableStrategy. This allows anyone to implement their own date decoding strategy and get the property wrapper behavior for free. Below are a few common Date strategies, but they also serve as a template to implement a custom property wrapper to suit your specific date format needs.

The following property wrappers are heavily inspired by Ian Keen.

ISO8601Strategy

ISO8601Strategy relies on an ISO8601DateFormatter in order to decode String values into Dates. Encoding the date will encode the value into the original string value.

Usage

struct Response: Codable {
    @DateValue<ISO8601Strategy> var date: Date
}

let json = #"{ "date": "1996-12-19T16:39:57-08:00" }"#.data(using: .utf8)!
let result = try JSONDecoder().decode(Response.self, from: json)

// This produces a valid `Date` representing 39 minutes and 57 seconds after the 16th hour of December 19th, 1996 with an offset of -08:00 from UTC (Pacific Standard Time).

RFC3339Strategy

RFC3339Strategy decodes RFC 3339 date strings into Dates. Encoding the date will encode the value back into the original string value.

Usage

struct Response: Codable {
    @DateValue<RFC3339Strategy> var date: Date
}

let json = #"{ "date": "1996-12-19T16:39:57-08:00" }"#.data(using: .utf8)!
let result = try JSONDecoder().decode(Response.self, from: json)

// This produces a valid `Date` representing 39 minutes and 57 seconds after the 16th hour of December 19th, 1996 with an offset of -08:00 from UTC (Pacific Standard Time).

TimestampStrategy

TimestampStrategy decodes Doubles of a unix epoch into Dates. Encoding the date will encode the value into the original TimeInterval value.

Usage

struct Response: Codable {
    @DateValue<TimestampStrategy> var date: Date
}

let json = #"{ "date": 978307200.0 }"#.data(using: .utf8)!
let result = try JSONDecoder().decode(Response.self, from: json)

// This produces a valid `Date` representing January 1st, 2001.

YearMonthDayStrategy

@DateValue<YearMonthDayStrategy> decodes string values into Dates using the date format y-MM-dd. Encoding the date will encode the value back into the original string format.

Usage

struct Response: Codable {
    @DateValue<YearMonthDayStrategy> var date: Date
}

let json = #"{ "date": "2001-01-01" }"#.data(using: .utf8)!
let result = try JSONDecoder().decode(Response.self, from: json)

// This produces a valid `Date` representing January 1st, 2001.

Or lastly, you can mix and match date wrappers as needed where the benefits truly shine

struct Response: Codable {
    @DateValue<ISO8601Strategy> var updatedAt: Date
    @DateValue<YearMonthDayStrategy> var birthday: Date
}

let json = #"{ "updatedAt": "2019-10-19T16:14:32-05:00", "birthday": "1984-01-22" }"#.data(using: .utf8)!
let result = try JSONDecoder().decode(Response.self, from: json)

// This produces two valid `Date` values, `updatedAt` representing October 19, 2019 and `birthday` January 22nd, 1984.

Installation

CocoaPods

pod 'BetterCodable', '~> 0.1.0'

Swift Package Manager

Attribution

This project is licensed under MIT. If you find these useful, please tell your boss where you found them.

bettercodable's People

Contributors

abonham avatar igorkulman avatar kinoroy avatar lickel avatar marksands avatar moyerr avatar nachosoto avatar nirma avatar oliverkrakora avatar rnapier avatar serjooo avatar stevensorial avatar tapi avatar yonaskolb avatar zeveisenberg avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

bettercodable's Issues

Addition of @KeyContainer for encoding/decoding dictionaries

Ole Begemann came up with a nice use case for fixing a shortcoming of Codable when dealing with Dictionaries that have a String based Enum key. Currently, these unexpectedly encode/decode as arrays rather than dictionary representations

https://gist.github.com/ole/5c31ca9e2919c815029784ef3b8fdc0d

If this is too specific of a use case, it might not make sense to include it, but I believe it solves a real problem that I have faced with Codable. What do you think about including this or a similar implementation? If you think it's useful, this package feels like a good home for it.

Composing `LossyArray` with `DefaultEmptyArray`

Hi

I have a need to be able to handle both

  1. lossy array (some items cant be decoded)
  2. default empty (for when the property itself is not present).

Issue

I tried to compose those with something like:

  @DefaultEmptyArray
  @LossyArray
  var items: [Item]

but I get the swift compiler error

Property type '[Model.Item]' does not match that of the 'wrappedValue' property of its wrapper type 'DefaultEmptyArray'

Cause

This seems because one of the two types arent able to wrap the other (both want to take the original T).

Proposed Fix

To fix this I have done the following:

struct DefaultLossyArray<T: Codable>: DefaultCodableStrategy {
  static var defaultValue: LossyArray<T> { .init(wrappedValue: []) }
}

typealias EmptyLossyArray<T> = DefaultCodable<DefaultLossyArray<T>> where T: Codable

with this addition I can hadle the above two cases well.

  @EmptyLossyArray
  @LossyArray
  var items: [Item]

Pull Request

Do you feel something like this is worth adding to BetterCodable?

Please let me know, I can send a PR w/tests etc.

Thanks!

Rename RawValue to DefaultValue in DefaultCodingStrategy

With the current naming the DefaultCodingStrategy can't be used with enums and types conforming to RawRepresentable. RawValue is an associated type that is used by the RawRepresentable protocol. Therefore if the DefaultCodingStrategy is implemented by an enum the defaultValue refers to the RawValue of that enum type which does not work with the DefaultCodable property wrapper since the types of wrappedValue and defaultValue have to match.

Here a little example:

enum VehicleType: String {
case car
case motorcycle
case unknown
}

extension VehicleType: DefaultCodableStrategy {
  static var defaultValue: String { // the compiler suggests this type
      return Vehicle.unknown
  }
}

struct Vehicle: Codable {
 let name: String
 @DefaultCodable<VehicleType>
 let vehicleType: VehicleType // compiler error
}

LoselessValue property cannot be used in normal init

Currently when you have a class with a property marked as @LosslessValue you cannot initialize the class "directly" via a custom init method as the property marked as @LosslessValue can only by initialized as Decodable.

JSONEncoder's `dateEncodingStrategy` ignored for default `Date`

I'm using a JSONEncoder with dateEncodingStrategy set to .iso8601 like this:

extension JSONEncoder {
  public static var iso: JSONEncoder {
    let encoder = JSONEncoder()
    encoder.dateEncodingStrategy = .iso8601
    return encoder
  }
}

My Codable type has a discoverDate property which I specify as @DefaultCodable:

@DefaultCodable<Date.DefaultToNow>
public var discoverDate: Date

The DefaultCodableStrategy I use is defined like this (I'm using Date() as the default value):

extension Date {
  public enum DefaultToNow: DefaultCodableStrategy {
    public static var defaultValue: Date { Date() }
  }
}

But for some reason, when I encode the object using JSONEncoder.iso, it ignores the dateEncodingStrategy which I set to iso8601 but it renders like I didn't set it. For example, my JSON output looks something like this:

{ "discoverDate" : 7200 }

But I would expect it to look like this:

{ "discoverDate" : "2001-01-01T02:00:00Z" }

I believe this is a bug. Any ideas how I can work around this?

Default Empty Lossy Array

Currently, you have to choose between:

  • Decoder not containing the array's key => @DefaultEmptyArray
  • Decoder contains the array's key, but one of the objects cannot be decoded => @LossyArray

But there is no possibility to have both behaviors.

For example:

Model:

struct User: Codable {
    var name: String
    var boughtArticles: [Article]
}

struct Article: Codable {
    var price: Int
}

Response JSON possibilities

{ 
  "name": "abc",
  "bought_articles": [
     { "price": 15 },
     { "proice": 10 } // Miss-typed key
  ]
}
  1. Because API is doing omitempty
{
  "name": "abc"
}

In this case, neither possibilities work properly.

  • @LossyArray would fail with the 2nd JSON
  • @DefaultEmptyArray would not fail, but it would be an empty array, and not contain the Article with price 10, that could've been correctly decoded.

What are your thoughts on this? How should it be handled?

I can create a @DefaultEmptyLossyArray, if there is no better option.

Support for Failables?

let json = """ [ {"name": "Taro", "age": 20}, {"name": "Hanako"} ] """.data(using: .utf8)! // Hanako has no "age"

Uncodable property wrapper

Hello,
please add non-codable property wrapper, as below, for properties that do not support codable protocol or do not want to decode / encode but can still be used and set separately.

/// Marks a property as non-codable and to be ignored
@propertyWrapper
struct Uncodable<Value> {
    
    private var value: Value?
    
    public init(wrappedValue: Value?) {
        self.value = wrappedValue
    }
    
    public var wrappedValue: Value? {
        get { value }
        set { self.value = newValue }
    }
}

extension Uncodable: Codable {
    
    public func encode(to encoder: Encoder) throws {
        // Skip encoding the wrapped value.
    }
    
    public init(from decoder: Decoder) throws {
        // The wrapped value is simply initialised to nil when decoded.
        self.value = nil
    }
}

thanks, grat project!

@DefaultCodable<> not working as expected?

`
struct DefToZero: DefaultCodableStrategy {
static var defaultValue: Double { 0.0 }
}

struct T : Hashable, Equatable, Codable {
@DefaultCodable var a : Double = 0.0
@DefaultCodable var b : Double = 0.0
}

struct C : Hashable, Equatable, Codable {
var t : T
}
`

When I run this, however, I get...

CodingKeys(stringValue: "a", intValue: nil) in Context(codingPath: [CodingKeys(stringValue: "t", intValue: nil), debugDescription: "No value associated with key CodingKeys(stringValue: \"a\", intValue: nil) (\"a\").", underlyingError: nil)

I've simplified things a bit, but this retains the jist. Should nested structs like this work? Am I right in expecting this to decode from a JSON that is missing the a member of the substruct t?

Are you prepared to support field mapping?

BetterCodable is very cool library, but I noticed that field mapping doesn't seem to be supported now? I have to keep the model fields and json fields unified, which may not be a good fit for our project.

Do you have any plans to support field mapping? This would help us to completely ditch the custom Codable implementation.

Using DefaultCodable as an example, you can add an optional String type parameter to the init(wrappedValue:) method.

Afterwards, the init(from:) and encode(to:) methods decide whether to use the singleValueContainer or container(keyedBy:) method depending on whether the field has a value or not.

@DefaultFalse when key is missing

I have an API which either sends {"bool":true} or no key at all. But I still like to have a non-optional Bool in my Codable class because I have to access it from Objective-C (which can't access optional Bools). Is that possible somehow? Thanks.

protocol CodableEnumeration for enum

Thank you for your code 👍。
The following code also works on my project,
If you think it's useful, this package feels like a good home for it 🤝。

protocol CodableEnumeration: RawRepresentable, Codable where RawValue: Codable {
    static var defaultCase: Self { get }
}

extension CodableEnumeration {
    public init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        do {
            let decoded = try container.decode(RawValue.self)
            self = Self.init(rawValue: decoded) ?? Self.defaultCase
        } catch {
            self = Self.defaultCase
        }
    }
    public func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        try container.encode(rawValue)
    }
}

Usage:

enum FreeType: Int, CodableEnumeration {
        
    case normal = 1
    case free = 2
    
    static var defaultCase: Self { .normal }
}

let type: FreeType?

Any ideas why I keep getting this error with cocoapods?

I have had this work once with the same project no issues. Then suddenly a pod install causes it to break. For whatever reason 0.1.0 works fine. Is this because the podspec is still saying s.version = '0.1.0'?

Our dep target is set to 12.4.

[!] CocoaPods could not find compatible versions for pod "BetterCodable":
  In snapshot (Podfile.lock):
    BetterCodable (= 0.1.0)

  In Podfile:
    ViewModels/Tests (from `Frameworks/ViewModels/`) was resolved to 0.1.0, which depends on
      BetterCodable (~> 0.2.0)

Specs satisfying the `BetterCodable (= 0.1.0), BetterCodable (~> 0.2.0)` dependency were found, but they required a higher minimum deployment target.

Purpose of LossyDecodableValue in LossyArray

I'm curious what the purpose of the LossyDecodableValue private struct is in the LossyArray wrapper. Since the generic T type is constrained to be a Codable type, couldn't the decoding in the wrapper be changed to:

let value = try container.decode(T.self)

I was playing around with this and it works as expected. Not sure I'm missing something and would appreciate some insight. Thanks!

Create a new release

The last commit occurred on Sep 12, 2022

0.4.0 was released on Jul 10, 2021
· 8 commits to master since this release

Would you be open to making a new release? In a newer build system I'm using, I kind of need a proper tag and cannot just point at a SHA. While I could obviously fork the repo to (just) create a tag, I'd prefer the canonical repo.

Thanks!

LosslessValue not working as excepted from Int to String value

Hi,

I've found an issue when using @LosslessValue from Int response.
We are currently upgrading our backend to a new API version and we need to handle both Int and String value for the id field.

To handle it properly we decided to set the id field with the @LosslessValue Property Wrapper.

Issue

struct Response: Codable {
    @LosslessValue var id: String
}

let json = #"{ "id": 1 }"#.data(using: .utf8)!
let result = try JSONDecoder().decode(Response.self, from: json)

print(result) // Response(id: "true")

The result for this example should be Response(id: "1") instead of Response(id: "true")
Note that everything works as excepted for int value > 1

Cause

This seems because of the decode priority in the types array in LosslessValue.swift

let types: [(Decoder) -> LosslessStringCodable?] = [
                decode(String.self),
                decodeBoolFromNSNumber(),
                decode(Bool.self),
                decode(Int.self),
                decode(Int8.self),
                decode(Int16.self),
                decode(Int64.self),
                decode(UInt.self),
                decode(UInt8.self),
                decode(UInt16.self),
                decode(UInt64.self),
                decode(Double.self),
                decode(Float.self)
            ]

As we can see the decodeBoolFromNSNumber() takes priority over the decode(Int.self)

Feature: Decode logical `Bool` into a real `Bool`

I've added a Bool type auto-conversion function, so if people want to add it to their projects, I'll try pulling requests.

JSON Swift
"false", "no", "0", "n", "f", 0, false false
"true", "yes", "1", "y", "t", 1, true true
import Foundation

@propertyWrapper
public struct BoolValue: Codable {
    public var wrappedValue: Bool

    public init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        if let stringifiedValue = try? container.decode(String.self) {
            switch stringifiedValue.lowercased() {
            case "false", "no", "0", "n", "f": wrappedValue = false
            case "true", "yes", "1", "y", "t": wrappedValue = true
            default:
                let description = "Expected to decode Bool but found a '\(stringifiedValue)' instead."
                throw DecodingError.dataCorruptedError(in: container, debugDescription: description)
            }
        } else if let integerifiedValue = try? container.decode(Int.self) {
            switch integerifiedValue {
            case 0: wrappedValue = false
            case 1: wrappedValue = true
            default:
                let description = "Expected to decode Bool but found a '\(integerifiedValue)' instead."
                throw DecodingError.dataCorruptedError(in: container, debugDescription: description)
            }
        } else {
            wrappedValue = try container.decode(Bool.self)
        }
    }

    public func encode(to encoder: Encoder) throws {
        try wrappedValue.encode(to: encoder)
    }
}

Usage:

@BoolValue var isFollow: Bool

Update BetterCodable Version

Hey Mark! I just tried to use BetterCodable on a package I'm working on and realized that adding the dependency this way .package(url: "https://github.com/marksands/BetterCodable.git", from: "0.0.0") is picking 0.0.1 without the latest changes. This is because the release tag points to an earlier commit. I think we might need to do another release to have everyone use the latest changes.

Missing property in nested object fails the whole decoding of nested object

Hi, I have a following sample structure of the object:

struct A: Codable {
    .
    .
    .
    @LossyOptional var objectB: B?
    .
    .
    .
}

struct B: Codable {
    .
    .
    .
    @LossyOptional var details: String?
    .
    .
    .
}

I am trying to decode object of type A and in case there is a missing details key in object B, I always get the whole B as a nil.
Shouldn't decoding make details equal to nil and continue to decode the rest of the properties?
Or am I getting it wrong?

[Question] Working with optional

Is there a way to combine the property wrapper with optionality?

Say I have

struct S {
     let timestamp: Date?
}

I want the timestamp property to be decoded using a custom strategy, but

struct S {
     @DateValue<TimestampStrategy> var timestamp: Date?
}

does not build because the timestamp property is optional.

Is there a way to make it work?

I tried defining a date strategy on optional types but that does not work.

Separate Decodable and Encodable?

Question

What are the options and thoughts on adding separate Decodable / Encodable support?

Problem

With the current implementation, everything relies on T: Codable.

So for example, the following code will not compile, because @DefaultEmptyArray requires ResponseObject to confirm to Encodable as well.

struct NetworkResponse: Decodable {
     @DefaultEmptyArray var someArray: [ResponseObject]
}

struct ResponseObject: Decodable {
    var age: Int
}

But I only care that NetworkResponse be Decodable, I don't need Encodable as well.

In order to make it compile. I need to conform/implement Encodable on ResponseObject.
It's trivial of course for the current ResponseObject, but when the object is more complex and uses a custom decoder initializer, I'm left with 2 bad options:

  • Spend time implementing the correct Encodable implementation, which will never be used
  • Leave a black/throwing implementation of the encode(into:) method, but then I lose compile time guarantee (which is the whole reason I'm using BetterCodable, so I don't have to write a bunch of useless guards)

Solutions

  • Ideal solution would be that DefaultCodable<Strategy<T>> would only require T to confirm to what the parent requires. In this case NetworkResponse only requires Decodable, so ResponseObject should only need Decodable.
    • However, I'm fairly certain there's no way to get parent types of a type (since ResponseObject could be used in 2 places, one requiring Decodable, the other one requiring Encodable)
  • The next solution would be to add 2 extra types for each property wrapper: DefaultDecodableEmptyArray etc. etc.
  • I don't know if there's anything else :\

[Feature request] LosslessArray

Similar to LosslessValue, just on working or arrays.

Example:

struct S {
    @LoselessArray var groupIds: [String]
}

would decode

{
    "groupIds": ["1","2","3"]
}

and also

{
    "groupIds": [1,2,3]
}

@DefaultFalse cannot deal string number

let data = """
    {"a": "1"}
    """.data(using: .utf8)!

struct A: Decodable {
    @DefaultFalse var a: Bool
}

let m = try JSONDecoder.init().decode(A.self, from: data)

print(m.a)  // print is false

but actual true is right answer

Decoding Date?

I have a field updatedON that comes as a nil value from the api, but gets updated in the local DB after an object is updated. Not sure how to handle this. Essentially I'd like to combine ISO8601Strategy and DefaultCodableStrategy

SnakeCaseCodingKey And CamelCase handling?

let json = """ {"user_id": "abc", "name": "tattn"} """.data(using: .utf8)!

For Upper Camel Case:

let json = """
{"UserId": "abc", "Name": "tattn"}
""".data(using: .utf8)!

How to deal with optional Date?

Tried:

@DateValue var cancellableUntil: Date?

This gives the error:

Property type 'Date?' does not match 'wrappedValue' type 'Date'

SwiftCodable organization

Hi @marksands, thanks for such a great library! I'm currently thinking of making XMLCoder more community-driven to encourage more contributions. I'm considering an umbrella organization (could name it https://github.com/SwiftCodable, but suggestions are welcome) that could host multiple libraries related to Codable, including XMLCoder and possibly your library? I hope this would be more than the sum of all parts, since this would also help discoverability for potential users and cross-pollination across those libraries. Would you be interested in such collaboration?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.