Mappable - Flexible JSON to Model converter, specially optimized for immutable properties

Overview

Mappable

Swift Swift Package Manager Build Status Codecov branch

Mappable is a lightweight, flexible, easy-to-use framework to convert JSON to model, specially optimized for immutable property initialization.

struct Flight: Mappable {
    let number: String
    let time: Date
    
    init(map: Mapper) throws {

        // with the help of @dynamicMemberLookup feature
        number = try map.id()
        time   = try map.time()

        // or use the old way
        // number = try map.from("id")
        // time   = try map.from("time")
    }
}
// Flight(JSONString: json)

A xcode plugin is also provided to genereate implementation automatically.

Features

  • JSON to object by just specifying mapping relationships
  • Optimized for immutable and optional
  • Flexible: easy to mix with manual initailization
  • Compatible types conversion : e.g. a Int property could be initialized with String value
  • Key path support

Why Another?

Most JSON to model libraries cannot handle immutable property initialization well. They require to declare properties with var and nullable types, which break the sprint of Swift and lead to bad code. Mappable was born for solving this problem.

Pros Cons
Codable - Native in Swift
- Automatic (no mapping relationships)
- support 2-direction conversion
- Inflexible
- Doesn't support inherented class
HandyJSON - Automatic (no mapping relationships)
- 2-direction conversion
No immutable properties support
ObjectMapper 2-direction conversion - Immutable properties support is weak*
- Multiple partterns led to chaos
- Missing support for some combinations of types.
SwiftyJSON Not a JSON object convertor.
It's only a convenient tool to deal with JSON data.

* 1) Cannot handle optional conveniently. 2) Doesn't support of compatible types conversion, which fall the whole object for every small mal-format in JSON.

Mappable is highly inspired by ObjectMapper. You could tread Mappable as an improved version of ImmutableMappable in ObjectMapper.

Usage

The basics

To support mapping, a type should implement Mappable protocol, which have only an initializer method:

class Country: Mappable {
    let name: String
    let cities: [City]   // struct City: Mappable { ... }
    let atContinent: Continent // enum Continent: Mappable { ... }
    
    required init(map: Mapper) throws {
        name        = try map.from("name")
        cities      = try map.from("city")
        atContinent = try map.from("location.continent")
    }
}

You just need write the mapping relationship: a key path for a property. Although these lines are just normal assignment statements, types aren't needed to specified, so you could tread these lines as a special representation of mapping relationships. (You could read the line as "try (to) map (value) from XXX" 😆 )

Then you could initialize a object like this:

// NOTE: these initializer throw errors, you should do error handling
let c = try Country(JSON: jsonDict)
let d = try? Country(JSONString: jsonString)

Supported types

  • Primitive types: Int, Double, String, Bool, URL, Date ...
  • Container types: Array, Dictionary, Set
  • Optional type
  • Enum, Struct, Object
  • Any combination of the types above

Default value

// just use `??`
cities = try map.from("city") ?? []

Optional handling

Optional types won't throw an error even if there's no corresponding date in JSON or the date is in mal-format. A nil will be assigned in this situation.

If you declare a property as an optional, it may mean this data isn't strictly required in JSON. So you wish to get a nil value if there's no data actually.

struct User: Mappable {
    let ID: String
    let summary: String?
    
    init(map: Mapper) throws {
        ID      = try map.from("id")
        summary = try map.from("summary")
    }
}
let json = ["id": "a123"]
let user = try! User(JSONObject: json) // It won't crash.

Compatible types conversion

Convert from
Int, Double, Float, CGFloat String
Bool Int, "true", "True", "TRUE", "YES", "false", "False", "FALSE", "NO", "0", "1"
String Int, NSNumber
URL String
Date Double(secondsSince1970), String (RFC 3339, e.g. 2016-06-13T16:00:00+00:00)

More detail at here.

Custom conversion

The content in initializer is just plain assignment, so you could do anything with the data. Use map.getRootValue() and map.getValue(keyPath:) to the get the raw JSON value and do what you want.

For convenient date conversion, there's also a options property in Mapper to set custom date strategy. (More complex example here)

Enum

Enums conforming RawRepresentable have a default implementation of Mappable. You just need to declare the conforming of Mappable to your enum types, then it will work.

For enum with associated values, you could do the manual implementation:

enum EnumWithValues: Mappable {
    case a(Int)
    case b(String)
    
    init(map: Mapper) throws {
        // It could be initialized with a json date like:
        // {"type": "a", value: 123}
        let value = try map.getValue("type", as: String.self)
        switch value {
        case "a":
            self = .a(try map.from("value"))
        case "b":
            self = .b(try map.from("value"))
        default:
            throw ErrorType.JSONStructureNotMatchDesired(value, "string a/b")
        }
    }
}

Class inheritance

class ChildModel: BaseModel {
    let b : Int
    required init(map: Mapper) throws {
        b = try map.from("b")
        try super.init(map: map)
    }
}

Nested key path

Use key path "AAA.BBB" to map a multi-level path value in JSON:

// let json = """ {"AAA": {"BBB": 1}} """
b = try map.from("AAA.BBB")

// use `n` to get a n-th value in array
// let json = """ {"AAA": [11,22,33]} """
b = try map.from("AAA.`2`") // b = 33

If a normal key contains . naturally, you could use like map.from("a.file", keyPathIsNested: false), to treat the key as a single-level path.

Installation

  • for Swift 5 & 4.2 : v1.3+
  • for Swift 4.1 and below : v1.2.2

Cocoapods

pod 'Mappable'

Swift Package Manager

.Package(url: "https://github.com/leavez/Mappable.git", from: "1.5.0"),

Carthage

github "leavez/Mappable"

License

Mappable is available under the MIT license. See the LICENSE file for more info.

You might also like...
Ss-json - High-performance json parsing in swift

json 0.1.1 swift-json is a pure-Swift JSON parsing library designed for high-per

Swift-json - High-performance json parsing in swift

json 0.1.4 swift-json is a pure-Swift JSON parsing library designed for high-per

Swift parser for JSON Feed — a new format similar to RSS and Atom but in JSON.

JSONFeed Swift parser for JSON Feed — a new format similar to RSS and Atom but in JSON. For more information about this new feed format visit: https:/

Model framework for Cocoa and Cocoa Touch

Mantle Mantle makes it easy to write a simple model layer for your Cocoa or Cocoa Touch application. The Typical Model Object What's wrong with the wa

AlamofireObjectMappe - An Alamofire extension which converts JSON response data into swift objects using ObjectMapper

AlamofireObjectMapper An extension to Alamofire which automatically converts JSON response data into swift objects using ObjectMapper. Usage Given a U

Functional JSON Parser - Linux Ready
Functional JSON Parser - Linux Ready

Functional JSON Parser Feature Linux Ready Type-safe JSON parsing Functional value transformation Easy to parse nested value Dependency free No define

Argo is a library that lets you extract models from JSON or similar structures in a way that's concise, type-safe, and easy to extend
Argo is a library that lets you extract models from JSON or similar structures in a way that's concise, type-safe, and easy to extend

Argo is a library that lets you extract models from JSON or similar structures in a way that's concise, type-safe, and easy to extend. Using Argo

Arrow  🏹 Parse JSON with style
Arrow 🏹 Parse JSON with style

Arrow 🏹 Parse JSON with style

Elevate is a JSON parsing framework that leverages Swift to make parsing simple, reliable and composable

Elevate is a JSON parsing framework that leverages Swift to make parsing simple, reliable and composable. Elevate should no longer be used for

Releases(1.5.0)
Owner
Leave
Leave
Dogtector: dog breed detection app for iOS using YOLOv5 model combined with Metal based object decoder optimized

Dogtector Project description Dogtector is dog breed detection app for iOS using YOLOv5 model combined with Metal based object decoder optimized for u

Bartłomiej Pluta 21 Aug 1, 2022
JSONNeverDie - Auto reflection tool from JSON to Model, user friendly JSON encoder / decoder, aims to never die

JSONNeverDie is an auto reflection tool from JSON to Model, a user friendly JSON encoder / decoder, aims to never die. Also JSONNeverDie is a very important part of Pitaya.

John Lui 454 Oct 30, 2022
A real-time cryptocurrency tracker and converter

CryptoRhino Run the .xcworkspace file Description: CryptoRhino is a real-time cryptocurrency tracker and converter. We track cryptocurrency prices in

Gregory Tolkachev 0 Nov 30, 2021
HandyJSON is a framework written in Swift which to make converting model objects to and from JSON easy on iOS.

HandyJSON To deal with crash on iOS 14 beta4 please try version 5.0.3-beta HandyJSON is a framework written in Swift which to make converting model ob

Alibaba 4.1k Dec 29, 2022
ObjectMapper is a framework written in Swift that makes it easy for you to convert your model objects to and from JSON.

ObjectMapper is a framework written in Swift that makes it easy for you to convert your model objects (classes and structs) to and from J

Tristan Himmelman 9k Jan 2, 2023
JSONExport is a desktop application for Mac OS X which enables you to export JSON objects as model classes with their associated constructors, utility methods, setters and getters in your favorite language.

JSONExport JSONExport is a desktop application for Mac OS X written in Swift. Using JSONExport you will be able to: Convert any valid JSON object to a

Ahmed Ali 4.7k Dec 30, 2022
🌟 Super light and easy automatic JSON to model mapper

magic-mapper-swift ?? Super light and easy automatic JSON to model mapper Finish writing README.md Ability to map NSManagedObject Ability to convert m

Adrian Mateoaea 26 Oct 6, 2019
Flexible JSON traversal for rapid prototyping

RBBJSON RBBJSON enables flexible JSON traversal at runtime and JSONPath-like que

Robb Böhnke 164 Dec 27, 2022
JSEN (JSON Swift Enum Notation) is a lightweight enum representation of a JSON, written in Swift.

JSEN /ˈdʒeɪsən/ JAY-sən JSEN (JSON Swift Enum Notation) is a lightweight enum representation of a JSON, written in Swift. A JSON, as defined in the EC

Roger Oba 8 Nov 22, 2022
JSON-Practice - JSON Practice With Swift

JSON Practice Vista creada con: Programmatic + AutoLayout Breve explicación de l

Vanesa Giselle Korbenfeld 0 Oct 29, 2021