Parsing Codable Responses With Alamofire 4
May 10, 2018 - Swift 4.0

It’s been a while since I wrote the previous tutorial. There are a few reasons for that but a big one is that I didn’t feel confident writing about Codable yet. It took a long time but I finally figured out why I was finding it so difficult. Often it just works but when it doesn’t you suddenly have to write a ton of not very obvious code, sometimes even to handle the stuff that was already working.

With more experience, I’m finding better ways to avoid writing as much custom code, like making the types for individual properties Codable instead of writing custom code for the top-level Codable item in my JSON. Like any language feature, it has some pros and cons so I didn’t want to just say “it’s great, use it all the time”. Now that I’ve had a chance to use Codable for varying projects, I’m comfortable making recommendations and writing up examples. Today we’ll look at handling Codable items in Alamofire responses.

Decode
(image by dylan nolte)

Parsing Codable Responses with Alamofire

As of now, Alamofire still doesn’t directly support Codable. The next version (Alamofire 5) will include support for parsing Codable responses but not for sending Codable parameters, so I’ve worked out my own ways to handle that. Here’s how handling Codable responses will look with Alamofire 5:

Alamofire.request(request)
  .responseJSONDecodable { (response: DataResponse) in
    print(response)
}

Until that’s released, we need to handle turning Alamofire responses into our Codable types ourselves. The Codable protocol is made up of 2 protocols: Encodable as well as Decodable. To create an item from JSON we don’t need Encodable so we can just use Decodable. I’ve been using an extension on JSONDecoder that works with the DataResponse<Data> that we get when we use Alamofire’s responseData response serializer:

extension JSONDecoder {
  func decodeResponse(from response: DataResponse) -> Result {
    guard response.error == nil else {
      print(response.error!)
      return .failure(response.error!)
    }

    guard let responseData = response.data else {
      print("didn't get any data from API")
      return .failure(BackendError.parsing(reason:
        "Did not get data in response"))
    }

    do {
      let item = try decode(T.self, from: responseData)
      return .success(item)
    } catch {
      print("error trying to decode response")
      print(error)
      return .failure(error)
    }
  }
}

After checking for errors and getting the Data from the response, it uses the generic type T to try to decode the item from the response: decode(T.self, from: responseData).

You can use that with any Decodable type within a .responseData response serializer by creating a decoder and calling decoder.decodeResponse(from: response), for example with the Todo struct that we used last time we looked at Codable:

Alamofire.request("https://jsonplaceholder.typicode.com/todos/")
  .responseData { response in
    let decoder = JSONDecoder()
    let todo: Result = decoder.decodeResponse(from: response)
}

Since we’re using a generic and not passing in the type, we need to specify the type of the response like let todo: Result<Todo> = .... If we try to do let todo = decoder.decodeResponse(from: response) then the compiler won’t be able to figure out what type it should be trying to create when decode(T.self, from: responseData) gets called.

That’s how I’m handling parsing JSON with Codable in Alamofire responses. The other half of Codable with Alamofire to handle is sending Encodable items as part of URL requests. We’ll tackle that in a future tutorial.

Want more Swift tutorials like this one?

Sign up to get the latest GrokSwift tutorials and information about GrokSwift books sent straight to your inbox

iOS Apps with REST APIs Cover

With iOS Apps with REST APIs ebook I’ll teach you how to build Swift apps that get their data from web services without hundreds of pages about flatmap and Core Whatever. iOS Apps with REST APIs ebook is the book I wish I had on my first iOS contract when I was struggling to figure out how to get the API data showing up in the app I was building.

Other Posts You Might Like