I’ve been really excited about Swift 4’s Codable since it landed earlier this year. Finally, now that the Xcode 9 GM is out, I’m ready to start converting the rather large Swift 3 project I work on day to day. Its full of the usual init?(dict: Dictionary<String,Any>) initializers you know and love.

Converting our model classes to Codable has been a big win and allowed me to delete a lot of code, but my API functions based around Alamofire and PromiseKit immediately broke without the custom dictionary initializers.

// The old
func getFeed() -> Promise<FeedPage> {
    return Alamofire.request("https://null.info/feed").responseJSON().then { json in
        guard let jsonDict = json as? Dictionary<String, Any>,
            let feedPage = FeedPage(dict: jsonDict) else {
                return Promise(error: NSError(domain: "net.skyebook", code: -1, userInfo: [NSLocalizedDescriptionKey: "Server Error"]))
        }
        
        return Promise(value: feedPage)
    }
}

While it worked, this old way is kind of gross. It requires you to manually initialize each object and to specify its type twice: once in the function signature’s return type (Promise<FeedPage>) and again when deserializing the response (FeedPage(dict:jsonDict)).

Since Codable provides us a uniform interface for deserialization, we can clean this up in a rather nice way that will be reusable across projects. The same way Alamofire gives us the really nice responseJSON() for returning a dictionary, let’s create a responseCodable(), which could return any class or struct which conforms to Codable.

extension Alamofire.DataRequest {
    // Return a Promise for a Codable
    public func responseCodable<T: Codable>() -> Promise<T> {
        
        return Promise { fulfill, reject in
            responseData(queue: nil) { response in
                switch response.result {
                case .success(let value):
                    let decoder = JSONDecoder()
                    do {
                        fulfill(try decoder.decode(T.self, from: value))
                    } catch let e {
                        reject(e)
                    }
                case .failure(let error):
                    reject(error)
                }
            }
        }
    }
}

This is a fairly routine use of generic types. The really cool bit is using it in practice. Since we already have a bunch of function signatures specifying the expected return type (in this case, a FeedPage), Swift can infer the generic type to use when calling responseCodable() based on the return type. Have a look:

// The new
func getFeed() -> Promise<FeedPage> {
    return Alamofire.request("https://null.info/feed", parameters: params).responseCodable()
}

This has allowed me to delete nearly 50% of the code in the API class and has turned out to be the really huge win in letting us delete boilerplate, error-prone code.