Blog

Swift Tip: Networking with Codable

In the very first Swift Talk we built a tiny networking library, leveraging Swift’s structs and generics for type-safety and testability. This was in June 2016, and we were still working with Swift 2.2. A lot has changed since then — so let’s revisit the code and make use of Swift’s latest tricks!

The basic idea was to separate the description of an endpoint from the code executing the network request. The description includes not only the URL, but also the function that can turn data from the network into the desired result:

struct Resource<A> {
    let url: URL
    let parse: (Data) -> A?
}

The parse function takes Data and turns it into an optional A. The advantage of using Data is that we can deal with any endpoint, irrespective of the data format. But let’s face it, more often than not we’re dealing with JSON. So we wrote the following initializer to make it easier to create JSON resources:

extension Resource {
    init(url: URL, parseJSON: @escaping (Any) -> A?) {
        self.url = url
        self.parse = { data in
            let json = try? JSONSerialization.jsonObject(with: data, options: [])
            return json.flatMap(parseJSON)
        }
    }
}

In the meantime Swift gained the Codable protocol that makes it super easy to encode and decode values conforming to it. As Aurélien Noce pointed out on Twitter, this makes a very nice addition to this tiny networking library. We can write another initializer on Resource for types that conform to the Decodable protocol:

extension Resource where A: Decodable {
    init(url: URL) {
        self.url = url
        self.parse = { try? JSONDecoder().decode(A.self, from: $0) }
    }
}

This makes it super easy to create resources for Decodable types. For example:

struct Episode: Codable {
    let id: String
    let title: String
}

let allEpisodes = Resouce<[Episode]>(url: url)
Webservice().load(allEpisodes) { print($0) }

Since arrays are also decodable if their elements are, we can create a resource for all episodes — including the function that parses data from the network — in a single line. In fact, we didn’t have to write any parsing code ourselves.

Of course this only works if you can determine how your data is being represented in JSON. In real projects you’ll often not have this possibility. However, it’s still a great technique for quick experiments and prototyping!

Stay up-to-date with our newsletter or follow us on Twitter.

Back to the Blog

recent posts