4 Essential Swift Networking Tools for Working with REST APIs

How to integrate AlamoFire with Multipart, SwiftyJSON, Image Caching, and Image Response Serialization to simplify your networking code

patch panel

Networking is hard, I’ll be the first to admit. It was an area I tended to avoid while learning Swift, even though I used to be a network administrator, managed web servers and created mobile APIs. At the suggestion of the Columbia iOS meetup group, I put together a Swift Network Starter Kit that integrates some online solutions into a template. This is a working example that integrates and demonstrates a few networking features useful for most projects. Use this to jump start your next test project in Swift.

Update: A lot has changed with Swift and Alamofire. Be sure to check out this updated blog post: Scrolling in Two Directions like Netflix, Part 2: Making API Calls which makes calls to IMDB using Alamofire, AlamofireImage, and SwiftyJSON.

1. AlamoFire

alamofire logo
AlamoFire is the networking library used in the template. It could take some time wrapping your head around AlamoFire due to the complex nature of networking, but this is a library worth learning.

Why use AlamoFire? First, it simplifies your network call syntax. Requests are chained to responses, so flow control is much easier to reason about than callbacks. Visually, it reminds me of Promises in JavaScript. Using this library over the API will make your code more compact and easier to read.

let url = "https://itunes.apple.com/us/rss/topfreeapplications/limit=10/json"
request(.GET, url)
    .responseJSON { (_, _, data, _) in
        println("data:: (data)")
    }

AlamoFire also makes it easier to pass data back and forth. Use parameter encoding to convert a Swift dictionary to URL parameters for GET, or a JSON body for POST. In the response, you can choose a JSON format which saves you the hassle of converting it yourself.

let params = [ "foo" : "bar" ]
request(.POST, "http://httpbin.org/post", parameters: params, encoding: .JSON)
    .responseJSON { (_, _, data, _) in
        println("data:: (data)")
    }

As you start adding more API endpoints, you end up with a lot of boilerplate code. AlamoFire has something called an URLRequestConvertible, which lets you generate requests programmatically. You can consolidate all your API URL endpoints into one place, giving you a single point of change for when you need to tweak a timeout or add an auth token.

Here’s what a simple router looks like:

enum Router: URLRequestConvertible {
    case FetchTopFree()
    var URLRequest: NSURLRequest {
        let (verb: String, path: String, parameters: [String: AnyObject]?) = {
            switch self {
            case .FetchTopFree():
                return ("GET", "https://itunes.apple.com/us/rss/topfreeapplications/limit=10/json", nil)
            }
        }()
        let URL = NSURL(string: path)!
        let URLRequest = NSMutableURLRequest(URL: URL)
        URLRequest.HTTPMethod = verb
        switch self {
        default:
            return ParameterEncoding.URL.encode(URLRequest, parameters: parameters).0
        }
    }
}

AlamoFire also supports Multipart now. Until recently, you had to fall back to AFNetworking, or build the request manually (which is not fun). I included a basic working example in the template, but the AlamoFire source code is a good resource if you need to dig into tailoring the call for your own API.

func createMultipart(image: UIImage, callback: Bool -> Void){
    // use SwiftyJSON to convert a dictionary to JSON
    var parameterJSON = JSON([
        "title": "foo",
        "description": "bar"
    ])
    // JSON stringify
    let parameterString = parameterJSON.rawString(encoding: NSUTF8StringEncoding, options: nil)
    let jsonParameterData = parameterString!.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true)
    // convert image to binary
    let imageData = UIImageJPEGRepresentation(image, 0.7)
    upload(
        .POST, 
        URLString: "http://httpbin.org/post",
        // you can swap out the http verb and URLString (above) for a URLRequestConvertible
        //Router.CreateMultipart(),
        multipartFormData: { multipartFormData in
            // fileData: puts it in "files"
            multipartFormData.appendBodyPart(fileData: jsonParameterData!, name: "goesIntoFile", fileName: "json.txt", mimeType: "application/json")
            multipartFormData.appendBodyPart(fileData: imageData, name: "file", fileName: "iosFile.jpg", mimeType: "image/jpg")
            // data: puts it in "form"
            multipartFormData.appendBodyPart(data: jsonParameterData!, name: "goesIntoForm")
        },
        encodingCompletion: { encodingResult in
            switch encodingResult {
            case .Success(let upload, _, _):
                upload.responseJSON { request, response, data, error in
                    let json = JSON(data!)
                    println("json:: (json)")
                    callback(true)
                }
            case .Failure(let encodingError):
                callback(false)
            }
        }
    )
}

let appleImage = UIImage(named: "apple")
createMultipart(appleImage!, callback: { success in
    if success { }
})

2. SwiftyJSON

pyramid of doom if let code

Dreaded if-let pyramid of doom when unwrapping JSON objects

Handling JSON in Swift is not pretty. You end up with an if-let pyramid of doom as you painstakingly peel back the layers of your JSON response. Fortunately, SwiftyJSON takes care of dynamic typing for you. With this library, you can safely pluck data from deeply nested JSON responses using compact, readable syntax.

let json = JSON(data!)
let label = json["feed"]["entry"][0]["im:name"]["label"].stringValue
println("label:: (label)")
// (console) label:: Minecraft: Pocket Edition

To learn more, I recommend this helpful Ray Wenderlich tutorial on working with JSON.

3. Image Caching

There’s a handful of image caching libraries out there to choose from. But there’s actually a very simple and stable implementation from NSHipster that leverages features already built into the API. This is the approach we use in this template.

Just put this in your AppDelegate’s didFinishLaunchingWithOptions:

let URLCache = NSURLCache(memoryCapacity: 4 * 1024 * 1024, diskCapacity: 20 * 1024 * 1024, diskPath: "cachedResponse")
NSURLCache.setSharedURLCache(URLCache)

And call this to cache your image response:

let cachedURLResponse = NSCachedURLResponse(response: response!, data: (data as NSData), userInfo: nil, storagePolicy: .Allowed)
NSURLCache.sharedURLCache().storeCachedResponse(cachedURLResponse, forRequest: request)

4. Image Response Serializer

If you find yourself pasting the same snippet of code every time you download an image, an Image Response Serializer could be the right tool for you. For example, you can cache the image after verifying that it downloaded completely. You can also convert the binary response to an UIImage for easy consumption.

extension Request {
    class func imageResponseSerializer() -> Serializer {
        return { request, response, data in
            if data == nil || response == nil {
                return (nil, nil)
            } else {
                if let contentLength = response?.allHeaderFields["Content-Length"] as? String {
                    if let data = data {
                        if contentLength == "(data.length)" {
                            let image = UIImage.safeImageWithData(data)
                            let cachedURLResponse = NSCachedURLResponse(response: response!, data: (data as NSData), userInfo: nil, storagePolicy: .Allowed)
                            NSURLCache.sharedURLCache().storeCachedResponse(cachedURLResponse, forRequest: request)
                            return (image, nil)
                        }
                    }
                }
                return (nil, nil)
            }
        }
    }

    func responseImage(completionHandler: (NSURLRequest, NSHTTPURLResponse?, UIImage?, NSError?) -> Void) -> Self {
        return response(serializer: Request.imageResponseSerializer(), completionHandler: { (request, response, image, error) in
            completionHandler(request, response, image as? UIImage, error)
        })
    }
}

request(.GET, appImageURL)
    .responseImage() { (request, _, image, error) in
        if error == nil && image != nil {
            cell.imageView?.image = image
        }
    }

This Ray Wenderlich tutorial not only covers Image Response Serializers, but it’s a great resource for learning AlamoFire as well.

Note that UIImage is not thread-safe, so you’ll also want to include some protective code in your serializer so you don’t crash whenever it tries to process more than one image at a time.

private let imageSync = NSLock()
extension UIImage {
    static func safeImageWithData(data:NSData) -> UIImage? {
        imageSync.lock()
        let image = UIImage(data:data)
        imageSync.unlock()
        return image
    }
}

Check out our repo

Our Swift Network Starter Kit is available on GitHub. It pulls the top ten free and paid apps from the iTunes API. There are also Post and Multipart buttons that show the payload reflected back from httpbin.org. The README has instructions on integrating it into your own project, and explains the code in more detail.

Demo of the Post and Multipart responses logged to the console:

network demo
Use it as a starter template for your own test projects, or just pull out bits and pieces you find useful. We’re open to any suggestions on how to make it better and easier to use, so feel free to add your thoughts to the comments.

Like this post? Please share it below! Then follow us on Twitter @thorntech and join our mailing list for future updates.

Patch Panel Image courtesy of Brent Hensarling on Flickr.

Get insights on SFTP Gateway, cloud computing and more, in your inbox.

Get smarter about all things tech. Sign up now!

Scroll to Top