Skip to content

Instantly share code, notes, and snippets.

@rnapier
Last active March 14, 2017 20:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rnapier/9fadd62e8440252fd55d5ad24bbec561 to your computer and use it in GitHub Desktop.
Save rnapier/9fadd62e8440252fd55d5ad24bbec561 to your computer and use it in GitHub Desktop.
public typealias JSON = [String:Any]
public enum JSONInitializableError: Error {
case initializationError(key: String)
}
public protocol JSONInitializable {
associatedtype Key: RawRepresentable
init(with json: JSON) throws
}
public extension JSONInitializable where Key.RawValue == String {
static func value<T>(for jsonKey: Key, in jsonObject: JSON) throws -> T {
guard let value = jsonObject[jsonKey.rawValue] as? T else {
throw JSONInitializableError.initializationError(key: jsonKey.rawValue)
}
return value
}
static func optionalValue<T>(for jsonKey: Key, in jsonObject: JSON) -> T? {
return try? value(for: jsonKey, in: jsonObject)
}
}
struct Address {
let streetName: String
let streetNumber: Int
let town: String
}
extension Address: JSONInitializable {
enum Key: String {
case streetName, streetNumber, town
}
init(with json: JSON) throws {
streetNumber = try Address.value(for: .streetNumber, in: json)
streetName = try Address.value(for: .streetName, in: json)
town = try Address.value(for: .town, in: json)
}
}
public struct Person {
let name: String
var age: Int
var address: Address?
}
extension Person: JSONInitializable {
public enum Key: String {
case name, age, address
}
public init(with json: JSON) throws {
name = try Person.value(for: .name, in: json)
age = Person.optionalValue(for: .age, in: json) ?? 0
address = try Person.optionalValue(for: .address, in: json)
.flatMap(Address.init(with:))
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment