dgrzeszczak/keyedcodable
*KeyedCodable* is an addition to swift's *Codable* and it's designed for automatic nested key mappings. The goal it to avoid manual implementation of *Encodable/Decodable* and make encoding/decoding easier, more readable, less boilerplate and what is the most important fully comp
Date formater example
Example JSON:
{
"date": "2012-05-01"
}Usage
struct DateCodableTrasform: Codable {
@CodedBy<DateTransformer> var date: Date
}Transformer
enum DateTransformer<Object>: Transformer {
static func transform(from decodable: String) -> Any? {
return formatter.date(from: decodable)
}
static func transform(object: Object) -> String? {
guard let object = object as? Date else { return nil }
return formatter.string(from: object)
}
private static var formatter: DateFormatter {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd"
return formatter
}
}Non codable formater example
You can even implement transformer for non Codable model and use it in you Codable tree like that:
Example JSON:
{
"user": 3
}Usage
struct DetailPage: Codable {
@CodedBy<UserTransformer> var user: User
}
struct User { // User do not implement Codable protocol
let id: Int
}Transformer
enum UserTransformer<Object>: Transformer {
static func transform(from decodable: Int) -> Any? {
return User(id: decodable)
}
static func transform(object: Object) -> Int? {
return (object as? User)?.id
}
}How to use?
To support nested key mappings you need to use ``KeyedKey` intead of `CodingKey` for your `CodingKeys` enums and `KeyedJSONEncoder`/`KeyedJSONDecoder` in place standard `JSONEncoder`/`JSONDecoder``. Please notice that Keyed coders inherit from standard equivalents so they are fully compatible with Apple versions.
Codable extensions
struct Model: Codable {
var property: Int
}Decode from string:
let model = try Model.keyed.fromJSON(jsonString)Decode from data:
let model = try Model.keyed.fromJSON(data)Endcode to string:
model.keyed.jsonString() Encode to data:
model.keyed.jsonData() You can provide coders in method parameters in case you need additional setup
Coders
You can also use Keyed coders the same way as standard versions.
let model = try KeyedJSONDecoder().decode(Model.self, from: data)let data = try KeyedJSONEncoder().encode(model)It's worth to mention that Keyed coders supports simple types ie. ``String`, `Int` etc. For example when we try to decode `Int` using standard `JSONDecoder``
let number = try JSONDecoder().decode(Int.self, from: data)it will throw an incorrect format error. Keyed version will parse that with success.
Keyed<> wrapper
There is a possibility to use standard JSON coders and still encode/decode KeyedCodables. To do that you have to use ``Keyed<>`` wrapper:
let model = try JSONDecoder().decode(Keyed<Model>.self, from: data).valuelet data = try JSONEncoder().encode(Keyed(model))It may be useful in case you do not have an access to coder's initialization code. In that situation your model may looks like that:
struct KeyedModel: Codable {
...
enum CodingKeys: String, KeyedKey {
....
}
....
}
struct Model {
let keyed: Keyed<KeyedModel>
}Manual nested key coding
In case you need implement Codable manually you can use ``AnyKey`` for simpler access to nested keys.
private let TokenKey = AnyKey(stringValue: "data.tokens.access_token")
struct TokenModel: Codable {
let token: Token
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: AnyKey.self)
token = try container.decode(Token.self, forKey: TokenKey)
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: AnyKey.self)
try container.encode(token, forKey: TokenKey)
}
}KeyedConfig
As mentioned earlier there is possibility to setup key options eg. delimiters on ``KeyedKey`` level but there is also possibility to setup it globally.
To do that you need to set the value of ``KeyedConfig.default.keyOptions``.
Beside key opptions there is also possibility to setup coders used by default in Codable extensions.
Migration to 3.x.x version
Version 3.0.0 is backward compatible with version 2.x.x however you have to use swift 5.1 for all new features connected with ``@PropertyWrapper``s.
Migration to 2.x.x version
Unfortunately 2.x.x version is not compatible with 1.x.x versions but I believe that new way is much better and it brings less boilerplate than previous versions. There is no need to add any manual mapping implementation, it's really simple so I strongly recommend to migrate to new version. All you need is to:
- use ``
KeyedJSONEncoder`\`KeyedJSONDecoder`instead of`JSONEncoder`\`JSONDecoder`` !! - change you CodingKeys to ``
KeyedKey`` and move your mappings here - remove ``
KeyedCodable`` protocol - remove constructor and map method
Package Metadata
Repository: dgrzeszczak/keyedcodable
Default branch: master
README: README.md