KPCC API Client: Refactoring, Documentation, and Usage

Jeff Campbell
KPCC Labs
Published in
7 min readJul 11, 2018

In my previous post I described the process of taking our new iOS app’s API client functionality and making it available in a nicely encapsulated framework for use in other projects.

Refactoring

While working on getting the framework set up, it became apparent that there were several areas ripe for improvement. I quickly decided that some changes were in order to make the API Client a more robust tool for our use.

Broadly speaking, these are the changes that I made as part of that transition:

  1. A lot of functionality offered by our server API was not exposed in the API Client, mostly because we don’t use it in our iOS app yet. This is an ongoing project — not all functionality is supported — but I took some time to add support for a broader set of our API’s features.
  2. I improved method signatures to better comply with Swift’s API design guidelines.
  3. There was not, initially, much in the way of error handling. Either a completion handler returned a struct (or array of structs, as the case may be) or it returned nil. This was fine to get started, but a much better pattern is to optionally return an enum value conforming to the Error protocol that provides information about an error. This allows the developer to better handle different classes of errors in divergent ways.
  4. Finally, last year (with Swift 4) we gained support for Codable, a protocol that provides language-level support for serializing and deserializing model objects to/from various formats. This includes JSON, the format we ingest from our API. This is a topic worthy of its own blog post — and one is coming soon! — as there are a number of gotchas to consider. Even so, Codable is tremendously powerful and allowed me to delete a lot of boilerplate JSON parsing code. I highly recommend it.

These changes took some time to complete (particularly switching to Codable), but the end result is an API client that is simpler, more powerful, and significantly more pleasant to use.

Documentation

Just as important as refactoring is documenting the work I’ve done.

For inline documentation, I used Swift’s own Markdown-flavored Swift documentation markup. For example:

Markdown-Based Inline Documentation Syntax

With the syntax above, API users can option-click a method to receive a brief description of what it does, see a quick example of the code in use, link to associated web documents (such as our KPCC server-side API documentation), as well as see what parameters the method takes.

Quick Help

(Note: Regarding the two “No description” items at the bottom, an Xcode bug currently prevents the use of markup for completion handler parameters. Hopefully this will be fixed soon.)

This also provides a brief method description when using Xcode’s autocomplete.

Autocomplete To The People!

You can also document properties. This is particularly useful for us as the purpose of some of our model struct properties isn’t always immediately obvious.

/// The program's host (ex. 'Larry Mantle')
public var host:String?
What’s a ‘Host’?

Not only does this provide obvious benefits to any developer becoming acquainted with an unfamiliar API, I’ve found that writing documentation also clarifies my conception of what a framework should do, helps me decide how it should be structured, and identifies weaknesses or missing functionality that users might expect.

Wait. Users?

Open Source

Yes, users. Hopefully including you!

I’m happy to announce that KPCC is open-sourcing our KPCC API Client, written in Swift, for use with your own projects! The client can be downloaded and added to your own project. You can do so here.

KPCC-API-Swift on GitHub

I hope that you will find new and clever uses for the KPCC API, submit pull requests for any improvements or fixes you might make (as the saying goes, “given enough eyeballs, all bugs are shallow”), and perhaps learn some tricks to make your own API client code better.

“A bustling street market in an Asian city” by Xavier Teo on Unsplash

Usage: Getting Started

First, I would recommend setting the debug level for the client to either basic or verbose to help with testing. This will print extra output to the console during runtime. You should disable it again before shipping.

KPCCAPICLient.shared.debugLevel = .basic

Right now, the KPCC API itself is pretty simple. All operations involve GET requests, and these exposed in the API Client as type methods under their associated content type, prefixed with the word “get” for easy autocompletion.

Below are some common usage scenarios.

Usage: Listing Programs

One common thing you might need to do is list all of the stellar programs KPCC currently provides to listeners. You can do so like this:

Program.get { (programs, error) in
if let programs = programs {
print(programs)
}
}

If you prefer to specify which kinds of programs you want to install (online-only programs, for instance) you can do with this method:

Program.get(programsWithStatuses: [.onlineOnly]) { (programs, error) in
if let programs = programs {
print(programs)
}
}

If you have a slug (a unique code used to identify a program), you can retrieve the associated program with it, like this:

Program.get(withProgramSlug: "airtalk") { (program, error) in
if let program = program {
print(program)
}
}

Usage: Episodes

Once you have programs, you’ll probably want information about recent on-demand episodes. You can retrieve these using a program’s slug this way:

Episode.get(withProgramSlug: "airtalk") { (episodes, error) in
if let episodes = episodes {
print(episodes)
}
}

A slightly longer version of this method can be used to specify the number of episodes and which page of results to return:

Episode.get(withProgramSlug: "airtalk", limit: 8, page: 1) { (episodes, error) in
if let episodes = episodes {
print(episodes)
}
}

If you have an episode ID, you can retrieve the associated episode in the following manner:

Episode.get(withID: 17883) { (episode, error) in
if let episode = episode {
print(episode)
}
}

Usage: Program Schedule

You can retrieve the current program schedule (starting Monday of the current week, with a length of 1 week) like this:

ProgramSchedule.get { (programSchedule, error) in
if let programSchedule = programSchedule {
print(programSchedule)
}
}

If you’d prefer to specify a custom start date and duration, you can do so like this:

ProgramSchedule.get(withStartDate: Date(), length: 86400) { (programSchedule, error) in
if let programSchedule = programSchedule {
print(programSchedule)
}
}

Usage: Articles

You can retrieve articles with specified types like this:

Article.get(withTypes: [.news, .blogs]) { (articles, error) in
if let articles = articles {
print(articles)
}
}

The following (rather lengthy, I admit) method allows you to retrieve articles fitting assorted criteria — such as, in this case, up to 10 news articles mentioning Steve Jobs. You can do so like this:

Article.get(withTypes: [.news], date: nil, startDate: nil, endDate: nil, query: "\"Steve Jobs\"", categories: nil, tags: nil, limit: 10, page: 1) { (articles, error) in
if let articles = articles {
print(articles)
}
}

(Note: The criteria used for retrieving articles this way are documented in the server API documentation for the articles endpoint. Also, note that phrase searches — ex. proper names — should be surrounded by quotes, as done above.)

If you know the unique ID for an article, you can retrieve it like this:

Article.get(withID: "asdf1234") { (article, error) in
if let article = article {
print(article)
}
}

Usage: Events

You can retrieve live events with specified types like this:

Event.get(withTypes: [.communityEnagement, .townHall]) { (events, error) in
if let events = events {
print(events)
}
}

If you want to constrain by an event’s start and end dates or limit the number returned, you can do so with the following method:

Event.get(withTypes: [.cultural], startDate: Date(), endDate: Date().addingTimeInterval(86400 * 30), limit: 10) { (events, error) in
if let events = events {
print(events)
}
}

Usage: Lists

Lists are a recent addition to our API repretoire — a collection of related programs, articles, or episodes. These are usually used for curated collections of content, such as the topical articles in our iOS app.

You can retrieve a collection of lists by context (ex. “iphone”, used by our iOS app) this way:

List.get(withContext: "iphone") { (lists, error) in
if let lists = lists {
print(lists)
}
}

You can also retrieve a list by ID, as long as it is active, with the method below:

List.get(withID: 1) { (list, error) in
if let list = list {
print(list)
}
}

There are a few other methods provided by the KPCC API Client (and more will be added over time!), but these should be enough to get you started. Learn more on the official GitHub repository page.

In my next post, I will dive into what the Codable protocol is, how adopting it improved this framework, and explain how you can use it in your projects. See you then!

--

--