TestsTested | ✗ |
LangLanguage | SwiftSwift |
License | MIT |
ReleasedLast Release | May 2017 |
SwiftSwift Version | 3.0 |
SPMSupports SPM | ✗ |
Maintained by Alex Hmelevski.
AHJSONSerializer is a framework written in Swift that makes it easy for you to convert your model objects (classes and structs) to and from JSON.
To support json decoding, a class or struct just needs to implement the JSONDecodable
protocol:
public protocol JSONDecodable {
init(decoder: AHJSONDecoder)
}
To support json encoding, a class or a struct need to implement the JSONEncodable
protocol:
public protocol JSONEncodable {
func encode(with encoder: AHJSONEncoder)
}
AHJSONSerializer uses the <~
and “~>”` syntaxic sugar operators to define how each member variable maps to and from JSON.
class User: JSONDecodable,JSONEncodable {
var username: String?
var age: Int?
var weight: Double!
var array: [AnyObject]?
var dictionary: [String : AnyObject] = [:]
var bestFriend: User? // Nested User object
var friends: [User]? // Array of Users
var birthday: Date?
required init(decoder: AHJSONDecoder) {
username <~ decoder["username"]
age <~ decoder["age"]
weight <~ decoder["weight"]
array <~ decoder["arr"]
dictionary <~ decoder["dict"]
bestFriend <~ decoder["best_friend"]
friends <~ decoder["friends"]
birthday <~ decoder["birthday"]
}
func encode(with encoder: AHJSONEncoder) {
username ~> encoder["username"]
age ~> encoder["age"]
weight ~> encoder["weight"]
array ~> encoder["arr"]
dictionary ~> encoder["dict"]
bestFriend ~> encoder["best_friend"]
friends ~> encoder["friends"]
birthday ~> encoder["birthday"]
}
}
struct Temperature: JSONDecodable {
let celsius: Double
let fahrenheit: Double?
init(decoder: AHJSONDecoder) {
celsius = decoder["temp_in_c"].value() ?? 0.0
fahrenheit = decoder["temp_in_f"].value()
}
}
Once your class implements JSONDecodable
and JSONEncodable
, AHJSONSerializer allows you to easily convert to and from JSON.
Convert a JSON string to a model object:
let user = Object(json: dictionary)
Convert a model object to a JSON dictionary:
let json = user.json
AHJSONSerializer can map classes composed of the following types:
Int
Bool
Double
Float
String
RawRepresentable
(Enums)Array<AnyObject>
Dictionary<String, AnyObject>
Object<T: JSONDecodable>
Array<T: JSONDecodable>
Array<Array<T: JSONDecodable>>
Set<T: JSONDecodable>
Dictionary<String, T: JSONDecodable>
Dictionary<String, Array<T: JSONDecodable>>
JSONDecodable
Protocolinit(decoder: AHJSONDecoder)
This function is where all mapping definitions should go. When parsing JSON, this function is executed during object creation. When generating JSON, it is the only function that is called on the object.
JSONEncodable
Protocolinit(decoder: AHJSONEncoder)
This function is where all encoding definitions should go. The function will be used when Object.json
will be called
AHJSONSerializer supports dot notation within keys for easy mapping of nested objects. Given the following JSON String:
"distance" : {
"text" : "102 ft",
"value" : 31
}
You can access the nested objects as follows:
func init(decoder: AHJSONDecoder) {
distance <~ map["distance.value"]
}
AHJSONSerializer supports map
function so you can do crazy stuff like:
struct Car: JSONDecodable, JSONEncodable {
let model: String
init(decoder: AHJSONDecoder) {
model = decoder["model"].map(transform: transformToInt)
.map(transform: increase)
.map(transform: transformToString)
.value() ?? ""
}
func encode(with encoder: AHJSONEncoder) {
model ~> encoder["firstName"].map{uppercased}
}
private func uppercased(str: String) -> String {
return str.uppercased()
}
}
*map function should be strong typed (no generics)
Classes that implement the JSONDecodable
and JSONEncodable
protocols can easily be subclassed. When subclassing mappable classes, follow the structure below:
class Base: JSONDecodable {
var base: String?
required init(decoder: AHJSONDecoder) {
base <~ map["base"]
}
}
class Subclass: Base {
var sub: String?
override init(decoder: AHJSONDecoder) {
super.init(decoder)
sub <~ map["sub"]
}
}
Make sure your subclass implemenation calls the right initializers and mapping functions to also apply the mappings from your superclass.
AHJSONSerializer can handle classes with generic types as long as the generic type also conforms to JSONDecodable
. See the following example:
class Result<T: JSONDecodable>: JSONDecodable {
var result: T?
required init(decoder: AHJSONDecoder) {
result <~ map["result"]
}
}
Contributions are very welcome
Before submitting any pull request, please ensure you have run the included tests and they have passed. If you are including new functionality, please write test cases for it as well.
To add AHJSONSerializer to a Swift Package Manager based project, add:
.Package(url: "hhttps://github.com/AlexHmelevski/AHJSONSerializer.git", majorVersion: 2, minor: 2),
to your Package.swift
files dependencies
array.
Alexei Hmelevski, [email protected]
AHJSONSerializer is available under the MIT license. See the LICENSE file for more info.