Introducing ExistAPI: An open-source Swift framework

Recently I released a new side project, called ExistAPI. It's a Swift framework to make working with the Exist API in iOS apps much easier. It's available via Cocoapods and the source is on GitHub.


I work with the Exist API a lot. Not just for our official iOS client, but also for all the side projects I create for fun and learning. I'm always making things that can sync data to Exist, and writing the code to talk to the Exist API over and over is a pain.

So I wanted to write a framework to abstract away that effort. But I also wanted to save myself (and other users of the framework) some effort. Because working with JSON in Swift can be a pain, even with Codable. It can take a lot of time to massage JSON into strongly-typed Swift, and if it's not the core part of your app, this could be enough hassle to make you avoid or put off integrating with our API.

So my framework handles this for you. It deserialises JSON returned from Exist and turns it into Codable models for you. So you only have to worry about Codable models in your own code.

And lastly, the framework wraps all Exist API calls in promises, using the PromiseKit library. This might seem confronting if you haven't worked with promises before, but they can be really simple once you get your head around how they work, and they make working with asynchronous code much easier. PromiseKit wraps asynchronous code and returns you a promise of whatever value will result from the asynchronous call when it's done. That means you can act on the result in an imperative way, as if it were synchronous.

Wrapping calls to the ExistAPI in promises means we can do some extra cool things. For example, we can use the PromiseKit when function to wait for several calls to be finished, and act on all their results at once:

let insightsPromise = existAPI.insights(days: 30)
let averagesPromise = existAPI.averages(limit: 30)
let correlationsPromise = existAPI.correlations()

when(fulfilled: [insightsPromise, averagesPromise, correlationsPromise])
    .done { insights, averages, correlations in
    // handle data
    }.catch { error in
    // handle errors just once for all these promises
    }

We can also chain calls together with PromiseKit, which is especially handy when first acquiring attributes from the Exist API, for example:

existAPI.acquire(names: ["weight"]
    .then { attributeResponse, urlResponse in
        guard let success = attributeResponse.success,
            success.contains("weight") else { return }
        let update = FloatAttributeUpdate(name: "weight", date: Date(), value: 65.8)
        existAPI.update(attributes: updates)
            .done { attributeUpdateResponse, urlResponse in
                // handle success
            }.catch { error in
                // handle error
            }
        }

But even if you don't want to bother with chaining calls together, the framework makes it easy to sync data from your iOS apps to Exist, or to read data from Exist accounts.

There are more examples and details of usage in the project's README. Issues are welcome for suggestions or questions!