Continuing where we left off in Bite #93 with our Alamofire Router, today we'll take a look at creating a Custom Response Serializer.

These are the mechanisms through which the Alamofire HTTP library translates the HTTP responses it receives into types that are more friendly to work with.

Alamofire ships with a few built-in serializers for common things like raw data, text, JSON and property lists. Today we'll be taking a look at adding our own. Let's get started.

We want to make it super easy to translate Alamofire responses into structs that conform to the Decodable protocol from the Decodable JSON parsing library. (Bite #86).

extension Alamofire.Request {
  public func responseCollection<T: Decodable>(completionHandler: Response<[T], NSError> -> Void) -> Self {
    let responseSerializer = ResponseSerializer<[T], NSError> { request, response, data, error in

      guard error == nil else { return .Failure(error!) }

      let result = Alamofire
        .Request
        .JSONResponseSerializer(options: .AllowFragments)
        .serializeResponse(request, response, data, error)

      switch result {
      case .Success(let value):
        do {
          return .Success(try [T].decode(value))
        } catch {
          return .Failure(Error.errorWithCode(.JSONSerializationFailed,
            failureReason: "JSON parsing error, JSON: \(value)"))
        }
      case .Failure(let error): return.Failure(error)
      }
    }

    return response(responseSerializer: responseSerializer, completionHandler: completionHandler)
  }
}

First we'll extend Request and add a new generic responseCollection function that returns a Response struct.

Notice that in the generic part of the function definition we allow any type T that confirms to the Decodable protocol.

Now the fun part. We'll first serialize the response using the built-in JSON response serializer, then switch on its result, returning the failure case if it exists.

If the JSON was parsed successfully, we'll try to decode using Decodable.

Now we can try both our Router and our new custom response serializer out together:

Alamofire.request(LBOC.Router.Bites)
  .responseCollection { (response: Response<[LBOC.Bite], NSError>) in
    guard response.result.error == nil else { return }

    let bites = response.result.value

    print(bites)
}

The responseCollection function handles arrays of objects. Making a responseObject serializer function to handle single object responses is almost identical. Simply replace all occurrences of [T] with T.