Adventures in App Building Part 1

Jonathan GravesJonathan Graves
2 min read

Is this thing on?

I’ve started working on a small app idea I’m calling Instalist. The general idea is a way to manage and generate playlists for Spotify that is hopefully more streamlined and automatic than the first party app.

The first piece I’d like to share might seem somewhat surprising: the Keychain. This API has been around for quite some time and is used to store anything that needs to be securely stored, such as API tokens, passwords, etc. In this case we’ll be focusing on storing Access and Refresh tokens that are retrieved from the Spotify API.

Why not use a third party library?

At first I thought about using an existing library such as keychain-swift, but I realized that would rob me of actually learning how the API works and I’ve also learned hard lessons in the past about taking dependencies on unnecessary third party libraries (does anyone remember LeftPad?).

High Level Design

The high level design I landed on is an enum named Keychain with an inner enum for Keys that strongly types the string keys that the underlying Apple Keychain API uses.

enum Keychain {

    enum Keys : String {
        case AccessTokenKey = "spotifyAccessToken"
        case RefreshTokenKey = "spotifyRefreshToken"
        case TokenExpirationKey = "spotifyTokenExpiration"
    }

    @discardableResult
    static func set(_ value: String, forKey key: Keychain.Keys) -> Bool {
        ...
    }

    static func string(forKey key: Keychain.Keys) -> String? {
        ...
    }

    @discardableResult
    static func clearValue(forKey key: Keychain.Keys) -> Bool {
        ...
    }
}

Some key takeaways:

  • I made this an enum because it’s a static-only utility and can never be instantiated by accident

  • The result is a Swifty API An example callsite might be Keychain.set(“foo”, forKey: Keys.Bar)

  • Having a strongly typed function string(forKey:) clearly demonstrates the pattern of additional strongly typed functions that we may need in the future.

  • clearValue(forKey:) is a necessary function because the Keychain API will throw an error if we try to set a duplicate value for an existing key (it’s used internally in the set function).

View the full implementation on Github

Why Start Here?

Because starting is the hard part. Writing about a tiny helper enum might not seem blog-worthy, but it lowered the bar just enough to hit publish. And if you’re building something—anything—you know how powerful that can be.

0
Subscribe to my newsletter

Read articles from Jonathan Graves directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Jonathan Graves
Jonathan Graves