The type Any in Swift does not conform to Codable because it can represent any type (whether codable or not). But, we run into situations where JSON objects are represented by a Dictionary<String, Any>, where Any here is limited to a set of known, codable-supporting types.
Now it’s possible to de/serialize JSON objects into/from their swift counterparts. A prime example where this might be used is with API’s that may have an expectation of a ‘reasonably’ defined response, but could userandomor unknown-at-runtime keys. When this is the case, type safety can’t be met, but the data is still valuable.
Interacting with the following Container definition and JSON snippet are now possible:
These same examples can apply to Array<Any> where Any represents one of the JSON compatible primptives:
String
Int
Double
Bool
As well as these containers, when composed of the same primitive types.
Array
Dictionary
Decoding Multiple Keys
During active development of projects, often times an API spec will change, or could possibly be inconsistent from one endpoint to another. It would be handy if our Swift models could be consistent, but support decoding of multiple possible entity models. With Codable+ this is possible.
Given the following:
struct CompanyV1: Decodable {
var name: String
var employees: Int
}
struct CompanyV2: Decodable {
var companyName: String
var employees: Int
var ceoName: String
private enum CodingKeys: String, CodingKey {
case name
case companyName
case employees
case ceoName
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
companyName = try container.decode(String.self, forKeys: [.name, .companyName])
employees = try container.decode(Int.self, forKey: .employees)
ceoName = try container.decodeIfPresent(String.self, forKey: .ceoName) ?? ""
}
}
let schema1json = """
{
"name": "Apple",
"employees": 42000
}
"""
let schema2json = """
{
"companyName": "Microsoft",
"employees": 600000,
"ceoName": "Satya Nadella"
}
"""
Notice the companyName = in the init(from:) method? This specifies multiple CodingKeys as possibilities. Now our CompanyV2 model supports decoding of our CompanyV1 schema.
Inspiration
Codable+ has grown and been inspired by several posts around the interwebs:
A collection of extensions around the Swift
Codable
implementation.Installation
Codable+ is distributed using the Swift Package Manager. To install it into a project, add it as a dependency within your
Package.swift
manifest:Then import Codable+ wherever you’d like to use it:
Usage
Decoding/Encoding
Dictionary<String, Any>
&Array<Any>
The type
Any
in Swift does not conform toCodable
because it can represent any type (whether codable or not). But, we run into situations where JSON objects are represented by aDictionary<String, Any>
, where Any here is limited to a set of known, codable-supporting types.Now it’s possible to de/serialize JSON objects into/from their swift counterparts. A prime example where this might be used is with API’s that may have an expectation of a ‘reasonably’ defined response, but could userandomor unknown-at-runtime keys. When this is the case, type safety can’t be met, but the data is still valuable.
Interacting with the following
Container
definition and JSON snippet are now possible:These same examples can apply to
Array<Any>
where Any represents one of the JSON compatible primptives:String
Int
Double
Bool
As well as these containers, when composed of the same primitive types.
Array
Dictionary
Decoding Multiple Keys
During active development of projects, often times an API spec will change, or could possibly be inconsistent from one endpoint to another. It would be handy if our Swift models could be consistent, but support decoding of multiple possible entity models. With Codable+ this is possible.
Given the following:
Notice the
companyName =
in theinit(from:)
method? This specifies multipleCodingKey
s as possibilities. Now ourCompanyV2
model supports decoding of ourCompanyV1
schema.Inspiration
Codable+ has grown and been inspired by several posts around the interwebs:
https://gist.github.com/mbuchetics/c9bc6c22033014aa0c550d3b4324411a
https://gist.github.com/loudmouth/332e8d89d8de2c1eaf81875cfcd22e24
https://stackoverflow.com/questions/47575309/how-to-encode-a-property-with-type-of-json-dictionary-in-swift-4-encodable-proto