How to Build API Driven iOS Apps in Swift Using Siesta
Time to read: 8 minutes
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:
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:
- Xcode 7 (latest version at time of writing is 7.3.1)
- Swift 2.2 (this is the version that ships with Xcode 7.3.1)
- CocoaPods for managing dependencies
- 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:
- Siesta Framework – the main workhorse of our app
- SwiftyJSON – makes working with JSON simpler in Swift
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!
Related Posts
Related Resources
Twilio Docs
From APIs to SDKs to sample apps
API reference documentation, SDKs, helper libraries, quickstarts, and tutorials for your language and platform.
Resource Center
The latest ebooks, industry reports, and webinars
Learn from customer engagement experts to improve your own communication.
Ahoy
Twilio's developer community hub
Best practices, code samples, and inspiration to build communications and digital engagement experiences.