Redis and Vapor With Server-Side Swift: Getting Started

Learn how to use the in-memory data store, Redis, and Vapor to cache objects by saving them in JSON, then configuring them to expire after a set time. By Walter Tyree.

Leave a rating/review
Download materials
Save for later
Share

Redis is the most popular key-value data store for high-performance storage and caching. In this tutorial, you’ll learn how to add Redis to a Vapor project to cache API responses. You’ll also explore some of the other features of Redis using the command-line interface (CLI).

To do this, you’ll add caching to a new web app: Your Daily Dog. This app fetches a new image of a cute dog to display on your site. At the beginning of the tutorial, the app retrieves a new dog record from the API for each page reload. By the end of the tutorial, you’ll ensure that everyone who visits during a set period of time will see the same dog picture.

When speed is critical, a Redis cache can help your app be “Best in Show”. Other tricks Redis can do include:

  • Storing session states
  • Replacing parts of a database
  • Maintaining a sorted list
  • Storing and brokering messages

This app uses data from The Dog API, which is a public API for viewing cute dog pictures. Hopefully you aren’t allergic to dogs. :]

This tutorial uses Leaf to render web pages. For more information about Leaf, read Templating Vapor Applications With Leaf.

Note: This tutorial assumes you have experience using Vapor to build web apps and are comfortable with the command line and Docker. If you are new to Vapor, check out the excellent Getting Started with Server-Side Swift With Vapor 4 tutorial. For a comprehensive tutorial on Docker, visit Docker on macOS: Getting Started.

Getting Started

Download the starter project by clicking the Download Materials button at the top or bottom of this tutorial, then navigate to the starter folder. The sample app has been tested on macOS and Ubuntu.

Open the Vapor app in Xcode by double-clicking Package.swift. If you’re not using Xcode, open Terminal and navigate into the starter folder. Then type swift build to pull all the dependencies and build the app. The project contains three folders:

  • Resources: Contains the web template used to render your app’s web page.
  • Tests: Contains a test for one of your routes.
  • Sources: Contains the source files for your Vapor app.

Open Sources/App/routes.swift. You’ll see two routes. app.get("hello") is a placeholder route to make sure your app is running and listening. A test in the Testing folder will exercise this route. app.get is the more exciting route. Here’s how it looks:

app.get { req -> EventLoopFuture<View> in
  //1
  let apiURL = URI("https://api.thedogapi.com/v1/images/search")
  //2
  return req.client.get(apiURL).flatMap { res -> EventLoopFuture<View> in
  //3
  guard let freshDog =
    try? res.content.decode(Array<Dog>.self).first else {
      return req.view.render("index")
    }
    //4
    return req.view.render("index", freshDog)
  }
}

This route does a few things. It:

  1. Defines apiURL to point to the endpoint, where it will fetch a dog record.
  2. Issues a get request to the URL.
  3. Attempts to decode the response from the DogAPI as Dog.
  4. Passes the decoded Dog to Leaf for rendering.

Next, go to Dog.swift, where the coding magic happens. By conforming to the Content protocol, Vapor automatically manages all the encoding and decoding for you. This lets you easily use the structs in your app.

Running the App

Enter swift run in the command line. On Linux, you may need to type swift run --enable-test-discovery, depending on what flavor and version combination you have.

For Xcode, you need to set the working directory so Vapor can find the Leaf template. To do that, open the scheme editor by left-clicking dailydog in the top bar to open the pop-up, then selecting Edit Scheme.

Scheme editor pop-up with Edit Scheme selected

Under Options, select Working Directory, then click the folder icon and select the root of your project.

Working directory option with the project root selected

Once you’ve selected your project, click Choose.

Working Directory window with the Choose button in the bottom-right

Now, build and run.

Xcode window with the starter project

Regardless of how you got your project running, use a web browser to navigate to localhost:8080 to enjoy a picture of a cute dog, like this one:

A cute dog on the website

Note: The API you’re using in this tutorial is maintained by regular people who take pictures of their dogs. Some of the records are not complete. You may see an error message on your web page like this: {"error":true,"reason":"expected array at key: breeds"}. If that happens, keep reloading the page until a dog appears.

Every time you reload the page, you’ll see another dog. Your next task will be to add Redis and use it to cache a dog so everyone can enjoy the same picture for a while.

Adding Redis

Vapor has built-in support for Redis, which uses RediStack behind the scenes. See the official documentation for more details.

Your first step is to open Package.swift. Then, add a dependency for the Vapor/Redis library in the dependencies section:

.package(url: "https://github.com/vapor/redis.git", from: "4.0.0"),

Now, link the package to an import product in the app’s dependencies section:

.product(name: "Redis", package: "redis"),

Now that you’ve imported the Redis library, you need to tell it where to find the Redis server. If you’re using Docker, the Redis server will be at localhost. When you use Redis in production, it will be at a different IP address.

Note: Redis is built for speed. When you plan your Redis setup, you want the Redis server as close to your Vapor app as possible. If Redis is at some remote data center and communicating over TCP/IP, you’ll lose its benefit.
To achieve maximum speed, Redis assumes that it’s in a trusted environment. That means it doesn’t encrypt things, as a slower database server might. You can learn more about securing Redis at the official documentation.

Open configure.swift and add Redis to the import statements at the top:

import Redis

Finally, initialize Redis on startup by replacing TODO: Configure Redis line with:

app.redis.configuration = try RedisConfiguration(hostname: "localhost")

Starting Docker

This tutorial assumes you have the Docker daemon installed and running. See the note at the beginning of this tutorial if you need help. Start a Docker Redis container by entering the following into the command line:

docker run --name dog-cache -p 6379:6379 -d redis

This creates a container named dog-cache running on the standard Redis port of 6379. The -d flag detaches the process from the current shell.

Return to routes.swift and add Redis to the import statements at the top:

import Redis

Next, find the app.get("hello") route and replace this line:

return req.eventLoop.makeSucceededFuture("Hello, world!")

with the following:

return req.redis.ping()

Build and run. This time, browse to localhost:8080/hello.

PONG output from Redis displayed in the web page

You’ll see the word PONG in an otherwise blank webpage. The /hello route executed the Redis .ping() command. The Redis server responded with PONG. This is the standard connectivity test, which you can learn more about in the Redis documentation.

So far, you’ve gotten Redis running and connected it to your Vapor app. However, when you refresh the web page at localhost:8080, the dogs keep changing. For your next step, you’ll update the app so that when you fetch the first dog, Redis will cache it and return the same dog on future requests.