Middleware Tutorial for Server-Side Swift Using Vapor 4: Getting Started

In this tutorial, you’ll learn how to create middleware — a module that sits between an app and the browser and removes some of the work load from your web app. By Walter Tyree.

Leave a rating/review
Download materials
Save for later

Middleware facilitates the single-responsibility principle by allowing you to create small modules with a sole purpose. In turn, this speeds up development, makes your code more modular and simplifies unit testing. In the context of a web server, middleware sits between the web app and the browser and performs tasks like logging and third-party authentication. This allows your web app to focus on its primary functions.

In this tutorial, you’ll enhance a Vapor project by adding middleware to a web app. By the end, you’ll

  • Understand the steps of creating middleware.
  • Know how to add an authorization mechanism to your backend.
  • Learn how to add formatted entries to server logs.
  • Be able to limit who can change the database of URLs.
  • End up with better and more useful logging.

You’ll do this all with an app, lnkshrtnr, which will be the next great startup success. Everyone can tell because it has a clever name! :]

lnkshrtnr allows anyone to create a shortened version of a long URL. When someone uses the shortened URL, lnkshrtnr will expand the link and redirect the browser to the long URL. Shortened links are popular in blog posts and conference talks because they take up less space.

Currently, though, lnkshrtnr has two major flaws. The first is anyone can add links, so malicious users can add dangerous links to the app. The second is the generic logging makes it hard to understand how the app is being used.

Note: This tutorial assumes you have experience using Vapor to build web apps and are comfortable with the command line and Docker. If you’re 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 works on macOS or Ubuntu.

This project consists of a database hosted in a Docker container for storing the link shortening information. It has a public GET route for redirecting links, along with administrative routes for adding and deleting database records. There are also tests.

Open the Vapor app in Xcode by double-clicking Package.swift. If you’re not using Xcode, open Terminal or your command line application if using Linux and navigate to the starter folder. Next, type swift build to begin the process of pulling down the dependencies and building the app. While your computer is downloading and building dependencies, explore the project.

At the root level, you’ll find LnkShrtn.postman_collection.json, which is a file containing some scripts for exercising the API using Postman.

Navigate to Sources/App and open the routes.swift file. Here, you’ll find the main public GET route of the app and a sample curl command to run if you aren’t using Postman. You’ll also find a line that looks like this:

try app.register(collection: AdminRoutes())

The project organizes all the administrative routes in a separate file. Open Sources/App/AdminRoutes.swift now. As with routes.swift, each route has a comment with a curl command to use as an example. The admin.post("shorten") route lets you pass in a key and a long URL to add to the database. It returns a status of conflict if the key already exists in the database, and a status of created if it successfully adds your data. There are also routes to delete and view records in the database.

Finally, open Sources/App/configure.swift and find the //TODO: Add Middleware line. After you create middleware, adding it to the app configuration applies it to all the traffic.

Once the system finishes downloading and building, it’s time to try everything out!

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 Postgres container using docker-compose.yml by typing the following into the command line for Mac:

docker compose up db

Or, if you’re using Linux, type the following:

docker-compose up db

If you don’t have Docker Compose installed, you can type the regular Docker command of:

docker run --name linkshrt-test \
-e POSTGRES_DB=vapor_test_database \
-e POSTGRES_USER=vapor_test_username \
-e POSTGRES_PASSWORD=vapor_test_password \
-p 5432:5432 -d postgres:latest

No matter how you get the database running, start the app server next. In Xcode, use Product > Run or Command-R. In Terminal, type swift run.

Note: Swift projects don’t have an .xcproject file, so Xcode may complain about missing resources and refuse to launch the project. Alternately, the project may launch, but the .env file containing important project-specific values won’t be found in the working directory and will cause the app to crash. The Vapor docs have a comprehensive webpage on how to modify your Scheme to designate the proper working directory.

In AdminRoutes.swift, inside of boot, you’ll find the curl commands required to create a shortened link. For example, look at this line:

-d '{"shortUrl": "test", "longUrl": "http://www.example.com"}'\

You’ll find the value test for the key shortUrl. This is the newly created shortened URL that will point to the value you place under the key longUrl — the value is currently http://www.example.com".

With both the database and the server running, use curl or Postman to add some links to the database. Then browse to localhost/yourShortUrlValue and try them out. Also, the eight tests in the test suite should pass.

Adding Middleware

As stated before, middleware will execute between the browser and the request handler. This means that code for handling a specific route can focus on that task; it doesn’t need to concern itself with authorization, file handling, logging or any other tasks. This is why middleware is a great example of the single-responsibility principle. Middleware instances sit between your router and the client connected to your server. This allows them to view, and potentially mutate, incoming requests before they reach your controllers. A middleware instance may choose to return early by generating its own response, or it can forward the request to the next responder in the chain. The final responder is always your router. When the response from the next responder is generated, the middleware can make any modifications it deems necessary, or choose to forward it back to the client as is. This means each middleware instance has control over both incoming requests and outgoing responses.

Middleware execution order