Heavily based on the Lyft implementation, this library has been refactored for Swift 5.0 and enables Swift Package.
Mapper is a simple Swift library to convert JSON to strongly typed objects. One advantage to Mapper over some other libraries is you can have immutable properties.
With Package Manager
.package(name: "Mapper", url: "https://github.com/polarcop/mapper.git", .upToNextMajor(from: "1.0.0"))
import Mapper
// Conform to the Mappable protocol
struct User: Mappable {
let id: String
let photoURL: URL?
// Implement this initializer
init(map: Mapper) throws {
try id = map.from("id")
photoURL = map.optionalFrom("avatar_url")
}
}
// Create a user!
let JSON: [String: Any] = ...
let user = User.from(JSON) // This is a 'User?'
enum UserType: String {
case Normal = "normal"
case Admin = "admin"
}
struct User: Mappable {
let id: String
let type: UserType
init(map: Mapper) throws {
try id = map.from("id")
try type = map.from("user_type")
}
}
struct User: Mappable {
let id: String
let name: String
init(map: Mapper) throws {
try id = map.from("id")
try name = map.from("name")
}
}
struct Group: Mappable {
let id: String
let users: [User]
init(map: Mapper) throws {
try id = map.from("id")
users = map.optionalFrom("users") ?? []
}
}
extension CLLocationCoordinate2D: Convertible {
public static func fromMap(_ value: Any) throws -> CLLocationCoordinate2D {
guard let location = value as? [String: Any],
let latitude = location["lat"] as? Double,
let longitude = location["lng"] as? Double else
{
throw MapperError.convertibleError(value: value, type: [String: Double].self)
}
return CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
}
}
struct Place: Mappable {
let name: String
let location: CLLocationCoordinate2D
init(map: Mapper) throws {
try name = map.from("name")
try location = map.from("location")
}
}
let JSON: [String: Any] = [
"name": "Polar HQ",
"location": [
"lat": 51.504949,
"lng": -0.019501,
],
]
let place = Place.from(JSON)
private func extractFirstName(object: Any?) throws -> String {
guard let fullName = object as? String else {
throw MapperError.convertibleError(value: object, type: String.self)
}
let parts = fullName.characters.split { $0 == " " }.map(String.init)
if let firstName = parts.first {
return firstName
}
throw MapperError.customError(field: nil, message: "Couldn't split the string!")
}
struct User: Mappable {
let firstName: String
init(map: Mapper) throws {
try firstName = map.from("name", transformation: extractFirstName)
}
}
struct User: Mappable {
let name: String
let JSON: AnyObject
init(map: Mapper) throws {
// Access the 'first' key nested in a 'name' dictionary
try name = map.from("name.first")
// Access the original JSON (maybe for use with a transformation)
try JSON = map.from("")
}
}
Mapper is maintained by Polar and released under the Apache 2.0 license. See LICENSE for details