---
title: Efficient JSON in Swift with Functional Concepts and Generics
teaser:
tags: ios,swift,osx
author: Tony DiPasquale
published_on: 2014-08-06
---

A few months ago Apple introduced a new programming language, [Swift], that
left us excited about the future of iOS and OS X development.  People were
jumping into Swift with Xcode Beta1 immediately and it didn't take long to
realize that parsing <abbr title="JavaScript Object Notation">JSON</abbr>,
something almost every app does, was not going to be as easy as in Objective-C.
Swift being a [statically typed] language meant we could no longer haphazardly
throw objects into typed variables and have the compiler trust us that it was
actually the type we claimed it would be. Now, in Swift, the compiler is doing
the checking, making sure we don't accidentally cause runtime errors.  This
allows us to lean on the compiler to create bug free code, but means we have to
do a bit more work to make it happy. In this post, I discuss a method of parsing
<abbr title="JavaScript Object Notation">JSON</abbr> <abbr title="Application
Programming Interface">API</abbr>s that uses functional concepts and
[Generics] to make readable and efficient code.

[Swift]: https://developer.apple.com/swift/
[statically typed]: http://en.wikipedia.org/wiki/Type_system
[Generics]: http://en.wikipedia.org/wiki/Generic_programming

## Request the User Model

The first thing we need is a way to parse the data we receive from a network
request into JSON.  In the past, we've used
`NSJSONSerialization.JSONObjectWithData(NSData, Int, &NSError)` which gives us
an optional <abbr title="JavaScript Object Notation">JSON</abbr> data type and a
possible error if there were problems with the parsing.  The <abbr
title="JavaScript Object Notation">JSON</abbr> object data type in Objective-C
is `NSDictionary` which can hold any object in its values.  With Swift, we have
a new dictionary type that requires us to specify the types held within. <abbr
title="JavaScript Object Notation">JSON</abbr> objects now map to
`Dictionary<String, AnyObject>`.  `AnyObject` is used because a <abbr
title="JavaScript Object Notation">JSON</abbr> value could be a `String`,
`Double`, `Bool`, `Array`, `Dictionary` or `null`.  When we try to use the <abbr
title="JavaScript Object Notation">JSON</abbr> to populate a model we've
created, we'll have to test that each key we get from the <abbr
title="JavaScript Object Notation">JSON</abbr> dictionary is of that model's
property type.

As an example, let's look at a user model:

```swift
struct User {
  let id: Int
  let name: String
  let email: String
}
```

Now let's take a look at what a request and response for the current user might
look like:

```swift
func getUser(request: NSURLRequest, callback: (User) -> ()) {
  let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in
    var jsonErrorOptional: NSError?
    let jsonOptional: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional)

    if let json = jsonOptional as? Dictionary<String, AnyObject> {
      if let id = json["id"] as AnyObject? as? Int { // Currently in beta 5 there is a bug that forces us to cast to AnyObject? first
        if let name = json["name"] as AnyObject? as? String {
          if let email = json["email"] as AnyObject? as? String {
            let user = User(id: id, name: name, email: email)
            callback(user)
          }
        }
      }
    }
  }
  task.resume()
}
```

After a lot of `if-let` statements, we finally have our `User` object.  You can
imagine that a model with more properties will just get uglier and uglier.
Also, we are not handling any errors so if any of the steps don't succeed, we
have nothing.  Finally, we would have to write this code for every model we want
from the API, which would be a lot of code duplication.

Before we start to refactor, let's define some `typealias`'s to simplify the
JSON types.

```swift
typealias JSON = AnyObject
typealias JSONDictionary = Dictionary<String, JSON>
typealias JSONArray = Array<JSON>
```

## Refactoring: Add Error Handling

First, we will refactor our function to handle errors by introducing the first
functional programming concept, the [`Either<A, B>` type].  This will let us
return the user object when everything runs smoothly or an error when it
doesn't.  We can implement an `Either<A, B>` type in Swift like this:

[`Either<A, B>` type]: https://hackage.haskell.org/package/base-4.2.0.1/docs/Data-Either.html

```swift
enum Either<A, B> {
  case Left(A)
  case Right(B)
}
```

We can use `Either<NSError, User>`as the type we'll pass to our callback so the
caller can handle the successfully parsed `User` or the error.

```swift
func getUser(request: NSURLRequest, callback: (Either<NSError, User>) -> ()) {
  let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in
    // if the response returned an error send it to the callback
    if let err = error {
      callback(.Left(err))
      return
    }

    var jsonErrorOptional: NSError?
    let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional)

    // if there was an error parsing the JSON send it back
    if let err = jsonErrorOptional {
      callback(.Left(err))
      return
    }

    if let json = jsonOptional as? JSONDictionary {
      if let id = json["id"] as AnyObject? as? Int {
        if let name = json["name"] as AnyObject? as? String {
          if let email = json["email"] as AnyObject? as? String {
            let user = User(id: id, name: name, email: email)
            callback(.Right(user))
            return
          }
        }
      }
    }

    // if we couldn't parse all the properties then send back an error
    callback(.Left(NSError()))
  }
  task.resume()
}
```

Now the function calling our `getUser` can switch on the `Either` and do
something with the user or display the error.

```swift
getUser(request) { either in
  switch either {
  case let .Left(error):
    // display error message

  case let .Right(user):
    // do something with user
  }
}
```

We will simplify this a bit by assuming that the `Left` will always be an
`NSError`.  Instead let's use a different type [`Result<A>`] which will either
hold the value we are looking for or an error.  It's implementation might look
like this:

[`Result<A>`]: http://hackage.haskell.org/package/HTTP-4000.2.17/docs/Network-Stream.html#t:Result

```swift
enum Result<A> {
  case Error(NSError)
  case Value(A)
}
```

In the current version of Swift (Beta 5), the above `Result` type will cause
[compiler errors].  Swift needs to know what types we'll be placing inside
the `enum`'s cases.  We can create a constant class to hold onto a generic
value for us.

[compiler errors]: https://devforums.apple.com/message/995261#995261

```swift
final class Box<A> {
  let value: A

  init(_ value: A) {
    self.value = value
  }
}

enum Result<A> {
  case Error(NSError)
  case Value(Box<A>)
}
```

Replacing `Either` with `Result` will look like this:

```swift
func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) {
  let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in
    // if the response returned an error send it to the callback
    if let err = error {
      callback(.Error(err))
      return
    }

    var jsonErrorOptional: NSError?
    let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional)

    // if there was an error parsing the JSON send it back
    if let err = jsonErrorOptional {
      callback(.Error(err))
      return
    }

    if let json = jsonOptional as? JSONDictionary {
      if let id = json["id"] as AnyObject? as? Int {
        if let name = json["name"] as AnyObject? as? String {
          if let email = json["email"] as AnyObject? as? String {
            let user = User(id: id, name: name, email: email)
            callback(.Value(Box(user)))
            return
          }
        }
      }
    }

    // if we couldn't parse all the properties then send back an error
    callback(.Error(NSError()))
  }
  task.resume()
}
```

```swift
getUser(request) { result in
  switch result {
  case let .Error(error):
    // display error message

  case let .Value(boxedUser):
    let user = boxedUser.value
    // do something with user
  }
}
```

Not a big change but let's keep going.

## Refactoring: Eliminate Type Checking Tree

Next, we will get rid of the ugly <abbr title="JavaScript Object
Notation">JSON</abbr> parsing by creating separate JSON parsers for each type.
We only have a `String`, `Int`, and `Dictionary` in our object so we need three
functions to parse those types.

```swift
func JSONString(object: JSON?) -> String? {
  return object as? String
}

func JSONInt(object: JSON?) -> Int? {
  return object as? Int
}

func JSONObject(object: JSON?) -> JSONDictionary? {
  return object as? JSONDictionary
}
```

Now the <abbr title="JavaScript Object Notation">JSON</abbr> parsing will look
like this:

```swift
if let json = JSONObject(jsonOptional) {
  if let id = JSONInt(json["id"]) {
    if let name = JSONString(json["name"]) {
      if let email = JSONString(json["email"]) {
        let user = User(id: id, name: name, email: email)
      }
    }
  }
}
```

Using these functions we'll still need a bunch of `if-let` syntax.  The
functional programming concepts [Monads], [Applicative Functors], and
[Currying] will help to condense this parsing.  First, let's look at the
Maybe Monad which is similar to Swift optionals.  Monads have a bind operator
which, when used with optionals, allows us to bind an optional with a function
that takes a non-optional and returns an optional.  If the first optional is
`.None` then it returns `.None`, otherwise it unwraps the first optional and
applies the function to it.

[Monads]: http://www.haskell.org/haskellwiki/Monad
[Applicative Functors]: http://www.haskell.org/haskellwiki/Applicative_functor
[Currying]: http://www.haskell.org/haskellwiki/Currying

```swift
infix operator >>> { associativity left precedence 150 }

func >>><A, B>(a: A?, f: A -> B?) -> B? {
  if let x = a {
    return f(x)
  } else {
    return .None
  }
}
```

In other functional languages, `>>=` is used for bind; however, in Swift that
operator is used for bitshifting so we will use `>>>` instead.  Applying this
to the <abbr title="JavaScript Object Notation">JSON</abbr> parsing we get:

```swift
if let json = jsonOptional >>> JSONObject {
  if let id = json["id"] >>> JSONInt {
    if let name = json["name"] >>> JSONString {
      if let email = json["email"] >>> JSONString {
        let user = User(id: id, name: name, email: email)
      }
    }
  }
}
```

Then we can remove the optional parameters from our parsers:

```swift
func JSONString(object: JSON) -> String? {
  return object as? String
}

func JSONInt(object: JSON) -> Int? {
  return object as? Int
}

func JSONObject(object: JSON) -> JSONDictionary? {
  return object as? JSONDictionary
}
```

Functors have an `fmap` operator for applying functions to values wrapped in
some context.  Applicative Functors also have an `apply` operator for applying
wrapped functions to values wrapped in some context.  The context here is an
`Optional` which wraps our value.  This means that we can combine multiple
optional values with a function that takes multiple non-optional values.  If
all values are present, `.Some`, then we get a result wrapped in an optional.
If any of the values are `.None`, we get `.None`.  We can define these
operators in Swift like this:

```swift
infix operator <^> { associativity left } // Functor's fmap (usually <$>)
infix operator <*> { associativity left } // Applicative's apply

func <^><A, B>(f: A -> B, a: A?) -> B? {
  if let x = a {
    return f(x)
  } else {
    return .None
  }
}

func <*><A, B>(f: (A -> B)?, a: A?) -> B? {
  if let x = a {
    if let fx = f {
      return fx(x)
    }
  }
  return .None
}
```

Before we put it all together, we will need to manually curry our `User`'s init
since Swift doesn't support auto-currying.  Currying means that if we give a
function fewer parameters than it takes, it will return a function that takes
the remaining parameters.  Our `User` model will now look like this:

```swift
struct User {
  let id: Int
  let name: String
  let email: String

  static func create(id: Int)(name: String)(email: String) -> User {
    return User(id: id, name: name, email: email)
  }
}
```

Putting it all together, our <abbr title="JavaScript Object
Notation">JSON</abbr> parsing now looks like this:

```swift
if let json = jsonOptional >>> JSONObject {
  let user = User.create <^>
              json["id"]    >>> JSONInt    <*>
              json["name"]  >>> JSONString <*>
              json["email"] >>> JSONString
}
```

If any of our parser's return `.None` then `user` will be `.None`.  This looks
much better, but we're not done yet.

Now, our `getUser` function looks like this:

```swift
func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) {
  let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in
    // if the response returned an error send it to the callback
    if let err = error {
      callback(.Error(err))
      return
    }

    var jsonErrorOptional: NSError?
    let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional)

    // if there was an error parsing the JSON send it back
    if let err = jsonErrorOptional {
      callback(.Error(err))
      return
    }

    if let json = jsonOptional >>> JSONObject {
      let user = User.create <^>
                  json["id"]    >>> JSONInt    <*>
                  json["name"]  >>> JSONString <*>
                  json["email"] >>> JSONString
      if let u = user {
        callback(.Value(Box(u)))
        return
      }
    }

    // if we couldn't parse all the properties then send back an error
    callback(.Error(NSError()))
  }
  task.resume()
}
```

## Refactoring: Remove Multiple Returns with Bind

Notice that we're calling `callback` four times in the previous function.  If we
were to forget one of the return statements, we could introduce a bug.  We can
eliminate this potential bug and clean up this function further by first
breaking up this function into 3 distinct parts: parse the response, parse the
data into <abbr title="JavaScript Object Notation">JSON</abbr>, and parse the
<abbr title="JavaScript Object Notation">JSON</abbr> into our `User` object.
Each of these steps takes one input and returns the next step's input or an
error.  This sounds like a perfect case for using bind with our `Result` type.

The `parseResponse` function will need a `Result` with `data` and the status
code of the response.  The iOS <abbr title="Application Programming
Interface">API</abbr> only gives us `NSURLResponse` and keeps the data separate,
so we will make a small struct to help out here:

```swift
struct Response {
  let data: NSData
  let statusCode: Int = 500

  init(data: NSData, urlResponse: NSURLResponse) {
    self.data = data
    if let httpResponse = urlResponse as? NSHTTPURLResponse {
      statusCode = httpResponse.statusCode
    }
  }
}
```

Now we can pass our `parseResponse` function a `Response` and check the response
for errors before handing back the data.

```swift
func parseResponse(response: Response) -> Result<NSData> {
  let successRange = 200..<300
  if !contains(successRange, response.statusCode) {
    return .Error(NSError()) // customize the error message to your liking
  }
  return .Value(Box(response.data))
}
```

The next functions will require us to transform an optional to a `Result` type
so let's make one quick abstraction before we move on.

```swift
func resultFromOptional<A>(optional: A?, error: NSError) -> Result<A> {
  if let a = optional {
    return .Value(Box(a))
  } else {
    return .Error(error)
  }
}
```

Next up is our data to <abbr title="JavaScript Object Notation">JSON</abbr>
function:

```swift
func decodeJSON(data: NSData) -> Result<JSON> {
  let jsonOptional: JSON! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &jsonErrorOptional)
  return resultFromOptional(jsonOptional, NSError()) // use the error from NSJSONSerialization or a custom error message
}
```

Then, we add our <abbr title="JavaScript Object Notation">JSON</abbr> to model
decoding on the model itself:

```swift
struct User {
  let id: Int
  let name: String
  let email: String

  static func create(id: Int)(name: String)(email: String) -> User {
    return User(id: id, name: name, email: email)
  }

  static func decode(json: JSON) -> Result<User> {
    let user = JSONObject(json) >>> { dict in
      User.create <^>
          dict["id"]    >>> JSONInt    <*>
          dict["name"]  >>> JSONString <*>
          dict["email"] >>> JSONString
    }
    return resultFromOptional(user, NSError()) // custom error message
  }
}
```

Before we combine it all, let's extend bind, `>>>`, to also work with the
`Result` type:

```swift
func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> {
  switch a {
  case let .Value(x):     return f(x.value)
  case let .Error(error): return .Error(error)
  }
}
```

And add a custom initializer to `Result`:

```swift
enum Result<A> {
  case Error(NSError)
  case Value(Box<A>)

  init(_ error: NSError?, _ value: A) {
    if let err = error {
      self = .Error(err)
    } else {
      self = .Value(Box(value))
    }
  }
}
```

Now, we combine all these functions with the bind operator.

```swift
func getUser(request: NSURLRequest, callback: (Result<User>) -> ()) {
  let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in
    let responseResult = Result(error, Response(data: data, urlResponse: urlResponse))
    let result = responseResult >>> parseResponse
                                >>> decodeJSON
                                >>> User.decode
    callback(result)
  }
  task.resume()
}
```

Wow, even writing this again, I'm excited with this result.  You might think,
"This is really cool. Can't wait to use it!", but we're not done yet!

## Refactoring: Type Agnostic using Generics

This is great but we still have to write this for every model we want to get.
We can use Generics to make this completely abstracted.

We introduce a `JSONDecodable` protocol and tell our function that the type we
want back must conform to that protocol.  The protocol looks like this:

```swift
protocol JSONDecodable {
  class func decode(json: JSON) -> Self?
}
```

Next, we write a function that will decode any model that conforms to
`JSONDecodable` into a `Result`:

```swift
func decodeObject<A: JSONDecodable>(json: JSON) -> Result<A> {
  return resultFromOptional(A.decode(json), NSError()) // custom error
}
```

Now make `User` conform:

```swift
struct User: JSONDecodable {
  let id: Int
  let name: String
  let email: String

  static func create(id: Int)(name: String)(email: String) -> User {
    return User(id: id, name: name, email: email)
  }

  static func decode(json: JSON) -> User? {
    return JSONObject(json) >>> { d in
      User.create <^>
        d["id"]    >>> JSONInt    <*>
        d["name"]  >>> JSONString <*>
        d["email"] >>> JSONString
  }
}
```

We changed our `User` decoder function to return an optional `User` instead of
a `Result<User>`.  This allows us to have an abstracted function that calls
`resultFromOptional` after a decode instead of having to call that in every
model `decode` function.

Finally, we will abstract the parsing and decoding from the `performRequest`
function for readability.  We now have our final `performRequest` and
`parseResult` functions:

```swift
func performRequest<A: JSONDecodable>(request: NSURLRequest, callback: (Result<A>) -> ()) {
  let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, urlResponse, error in
    callback(parseResult(data, urlResponse, error))
  }
  task.resume()
}

func parseResult<A: JSONDecodable>(data: NSData!, urlResponse: NSURLResponse!, error: NSError!) -> Result<A> {
  let responseResult = Result(error, Response(data: data, urlResponse: urlResponse))
  return responseResult >>> parseResponse
                        >>> decodeJSON
                        >>> decodeObject
}
```

## Further Learning

The example code is available on [GitHub].

[GitHub]: https://github.com/thoughtbot/FunctionalJSON-swift/tree/d3fcf771c20813e57cb54472dd8c55ee33e87ae4

If you are curious about functional programming or any of the concepts discussed
in this post, check out [Haskell] and specifically [this post] from the [Learn
You a Haskell] book.  Also, check out [Pat Brisbin's post] about options parsing
using the Applicative.

[Haskell]: http://www.haskell.org/haskellwiki/Haskell
[this post]: http://learnyouahaskell.com/functors-applicative-functors-and-monoids
[Learn You a Haskell]: http://learnyouahaskell.com/
[Pat Brisbin's post]: https://thoughtbot.com/blog/applicative-options-parsing-in-haskell
