Today we’re excited to release Mapper, Lyft’s first of many open source libraries for iOS written in Swift.

Ever since Swift was released, parsing JSON has been a hot topic. At Lyft, when we completely rewrote our app in Swift, we wanted to find a simple way to solve this problem. Unfortunately, at the time there weren’t any open source libraries that fit our needs. So we ended up writing our own library to do this.

The first version of this internal library looked like this:

public struct User {

public var id: String = ""

public var firstName: String?

public var photoURL: NSURL?



public init() {}

}



extension User: Mappable {

public mutating func map(mapper: Mapper) {

id « mapper["id"]

firstName « mapper["firstName"]

photoURL « mapper["photoURL"]

}

}



var user = User() // An empty 'User'

user.map(JSON) // A hopefully valid 'User'

Overall this worked well for us, but we had 3 major issues with this approach.

All our model properties had to be mutable. We want to enforce immutability wherever possible, especially for model objects, and we weren’t able to with this library. You could partially fix this by using private(set) on properties, but putting that everywhere made the code pretty ugly. We couldn’t conditionally return a User. Since we were first initializing an empty user, then filling it with JSON, we’d always return a non-optional User, even if the data we received from the server was invalid. Because we were always returning a non-optional User, we were forced to add default values for any properties we wanted to be non-optional. As you can see in the example above we defaulted the User’s id to an empty string. Meaning we were pushing this data problem to the rest of our application if we got bad data from the server.

Because of these limitations, we put it on our to-do list to see if we could come up with a new Mapper that allowed us to use immutable properties. Then, when Swift 2.0 was released with the new error handling we came up with a new way to handle JSON. Using the same example from above, it now looks like this:

public struct User {

public let id: String

public let firstName: String?

public let photoURL: NSURL?

}



extension User: Mappable {

public init(map: Mapper) throws {

try id = map.from("id")

firstName = map.optionalFrom("firstName")

photoURL = map.optionalFrom("photoURL")

}

}



let user = User.from(JSON) // This is a 'User?'

Here we’re able to lean on the new error handling features of Swift 2 in order to fix all of the previous issues.

Now all of our properties can be immutable since we’re initializing our model objects with the JSON. We can now fail to create a User if any required keys aren’t in the response, or aren’t the expected type. We no longer need default values for these required keys; instead we fail to initialize the User.

We believe this new Mapper is a simple, elegant way to handle parsing JSON in Swift and we hope you do too!

Get started with Mapper on Github

Interested in open source work and having a big impact? Lyft is hiring! Hit me up on Twitter or at keith@lyft.com.

N E X T → Announcing Confidant, an open source secret management service from Lyft