How to Build API Driven iOS Apps in Swift Using Siesta

There are so many wonderful APIs out there but they aren’t always easy to work with in mobile apps. The Siesta framework makes using APIs in Swift apps a joy.

Patterns for using REST APIs in mobile apps tend to focus on requests but the ‘R’ that matters most in REST is Resource. Siesta provides an app-wide observable model of a RESTful resource’s state which answers the following three questions:

  • What is the latest data for this resource, if any?
  • Did the latest request result in an error?
  • Is there a request in progress?

Not only does it answer those questions but as soon as one changes it broadcasts answers to anything interested in listening to them. It also caches the results so you don’t make the same network request twice unless you need to.

Since everyone’s still going crazy about Pokémon Go we’ll build an API-driven Pokédex in this post. We’ll use the Pokéapi to build our Pokédex. When it’s done it’ll look like this:

pokedex

Let’s get started so we can catch ‘em all.

What You’ll Need

Before we can get started you’ll want to make sure you have some prerequisites ready to go. Here’s a list of what you’ll need for the Pokédex:

  1. Xcode 7 (latest version at time of writing is 7.3.1)
  2. Swift 2.2 (this is the version that ships with Xcode 7.3.1)
  3. CocoaPods for managing dependencies
  4. This starter project from Github which contains some pre-built user interface screens and project structure to save some work in this tutorial. We’ll clone this in the next step.

Setting Up the Project

To get started, clone the starter project repo:

The starter project contains a Podfile that describes the CocoaPods dependencies our project needs to include. The two dependencies we need in this app are:

Run the following command in the starter project’s directory to install the dependencies using CocoaPods:

Note: If you get an error trying to install the pods you may need to run pod repo update to refresh the local CocoaPods spec repo. This might take a while.

If you want to know more about CocoaPods you can read this blog post. Open the PokeapiDex.xcworkspace file that CocoaPods in Xcode by running open PokeapiDex.xcworkspace. Build the project once before we get started to resolve the dependencies inside of Xcode. If you don’t do this Xcode won’t provide completions for the dependencies we added using CocoaPods.

Now that we have the Siesta framework for working with APIs and SwiftyJSON for easier JSON processing we can dive into creating our Pokédex.

Creating a Siesta Service

A Service in the Siesta framework represents an API. We need to create one to represent the Pokeapi. Create a new iOS Swift file (iOS->Source->Swift) in the API folder called Pokeapi.swift. We’ll create the Pokeapi Service as a singleton to be used anywhere in the project. We’ll use a private init() function so that _Pokeapi can only be instantiated from this source file.

Replace the contents of Pokeapi.swift with the following code:

This code creates a Service representing the API found at https://pokeapi.co/api/v2. It configures the service to parse responses from the API using SwiftyJSON by hooking into Siesta’s robust transformer pipeline. We also set the expiration time of the cache to 1 hour for all resources since our data won’t actually change. The default of 30 seconds makes much more sense for an API which has contents that change frequently.

With our Service created we can start working with the resources that are available in the Pokeapi.

Setting Up Siesta Resources

A Resource is a local cache of a RESTful resource from the API. It holds the data for the resource as well as status details about the network requests related to it. We’ll use Resource objects to fetch info about the first 151 Pokemon in the Pokeapi. First, update the init() method in the _Pokeapi() Service to configure a transformer for the /pokemon endpoint of the Pokeapi by adding the highlighted code:

The highlighted code takes the response from any request to /pokemon and returns the SwiftyJSON array representation of the results value. Next let’s add a Resource property to our Service called pokedex. Put this code after the closing tag for the init method:

This Resource property will fetch the first 151 Pokémon from the Pokeapi and make them available to any object that observes them. The PokedexViewController will use this Resource to display the list of Pokémon in a UITableView. Let’s wire that up now so we can see Siesta in action.

Gotta List ‘em All

Now that we have a Resource that returns JSON, let’s display it in our PokedexViewController. Head over to PokedexViewController.swift and replace the placeholder line that says var objects = [AnyObject]() with the following code:

The pokemonList variable will be loaded on a background thread so we use didSet to reload our table view once the list has been loaded. Siesta has a UI helper called ResourceStatusOverlay that will provide a progress indicator when the list is being fetched as well as a mechanism to retry a request if it fails. Let’s add that to the top of PokedexViewController:

Then, add the following highlighted line to viewDidLoad:

Now we’ll hook up the pokedex Resource to populate our pokemonList array. Add the following code to the top of the PokedexViewController class making sure to add the ResourceObserver protocol to the class declaration:

When the pokedexResource property is set it does the following things:

  • Removes any existing observers
  • Adds self and the status overlay as observers
  • Loads the data for the resource if needed based on the cache expiration timeout

The resourceChanged() function will be called when the resource broadcasts a change event. This usually means new data is available. The typedContent() function is a convenience method that returns a type-casted value for the latest result for the Resource if available or nil if it’s not. In our case it’s a SwiftyJSON array of Pokémon ready to be displayed in the table view. In viewDidLoad we set the pokedexResource property to the Pokeapi.pokedex resource we declared in our service which kicks the whole resource fetching process off.

Now we can display the list in our tableView. Replace the table view functions with the following code:

This is standard UITableViewController code. We have one section that contains a number of rows set to the number of Pokémon in pokemonList. In the tableView:cellForRowAtIndexPath function we get the Pokémon summary JSON that corresponds with that row. We then use SwiftyJSON to get the name out of the JSON and capitalize it and set it as textLabel.text. Then we display the id of the Pokémon in detailTextLabel.text.

Build the app and you should see a loading indicator while Siesta fetches the Pokémon list and then you will see this:

(Because of high demand, the PokéApi might be slow to respond and it has gone down a few times. You might have to be patient and try the request again.)
Now that we have a list of Pokémon it would be really great to see more details about them. First we’re going to need to create a data model for a Pokémon.

Gotta Model ‘em All

We built the Pokémon list using JSON data because we only had one field to work with. For our Pokémon details screen we’re going to be working with more properties so let’s create a model for the Pokémon data. The Pokeapi is going to return us data in JSON format and we’ll want to represent that data in Swift data structures.

Create a new Swift File in the Models folder called Pokemon.swift. For each Pokemon we will store the name, sprite image URL and the two types the Pokemon is characterized by (grass, poison, etc.). Replace the contents of Pokemon.swift with the following struct:

The initializer takes in JSON as a parameter and sets the Pokémon’s properties using SwiftyJSON. Note that the types and spriteUrl properties are optionals. This is because they might not exist for a given Pokémon.

Let’s retrieve the Pokémon JSON using another Siesta Resource. Head back to Pokeapi.swift and add the following configureTransformer code to the init() function:

This transformer will take any resource that accesses a Pokémon (i.e. the /pokemon/* endpoint of the API where * is the id of the Pokémon) and pass the JSON to the Pokemon struct’s initializer. This means we can create a Resource that returns an instance of a Pokemon struct. Add the code to do just that to the bottom of the _Pokeapi class:

This code allows us to call Pokeapi.pokemon("1") to get a Resource for the Pokémon with id=1. Let’s use that to load the details page with our Pokémon data.

Gotta View ‘em All

Open up PokemonViewController.swift and change the class declaration to add the ResourceObserver property:

Next, add the StatusOverlay just like we did for PokedexViewController:

Now we’ll use the Resource we created to load up the Pokémon data. Add this code just below the IBOutlets at the top of the file:

This Pokémon Resource works just like the Pokedex list did with the added nicety that we now have access to a Pokemon model. When the resourceChanged function is called the showPokemon() function checks to see if pokemon is not nil. If it’s not nil the _pokemon variable is used to populate the UI for the Pokémon. Add a call to showPokemon() in viewDidLoad:

All that’s left to do is to show PokemonViewController when a Pokémon is tapped in PokedexViewController. Replace the prepareForSegue function in PokedexViewController with the following code:

This code sets the pokemonResource property on the destination PokemonViewController with a call to Pokeapi.pokemon(id) passing in the id for the tapped Pokémon.

Run the app and tap on a Pokémon. You should see the familiar loading indicator and then you’ll see the Pokémon’s details load like this:


The first time a Pokémon loads it is fetched from the API but if you tap on it again it will load immediately since Siesta caches the value in memory. That’s it, you built a mini-Pokédex using Pokeapi and the Siesta framework. Now go out there and catch ‘em all!

What’s Next?

With the aid of SwiftyJSON and Siesta we were able to create an API-driven Pokédex based using Pokeapi.co. Siesta removes a lot of boilerplate networking code and focuses on managing the resources in the API you’re working with. This means we were able to focus mostly on app logic and way less on writing network code.

I hope you’re excited to try more things with the Siesta framework. Here are some ways you could improve on this Pokédex:

  • Add more Pokémon attributes to the details page
  • Add sprite images to the Pokédex list
  • Write the Pokémon to disk using a persistent cache so that it works offline

Let me know what you decide to build. You can find me on Twitter @brentschooley or email me at brent@twilio.com. Happy Pokémon hunting!

  • Carl Smith

    I followed the tutorial up to the point where I should have seen entries in the Pokedex
    table view. I double-checked my code to be sure I had done everything correctly.

    When I ran the app (both in the simulator and on my iPhone 6), I received the following errors: “Unable to load data. Service unavailable. Try again.” I saw the errors very quickly, so quickly that I wondered if the request was even being sent.

    I can send requests to the pokeapi successfully (and quickly receive responses) in Safari. Any thoughts on how to troubleshoot?

    I’ll gladly provide my code, if it helps to narrow down what the problem is.