Building Your Web App in Swift Using Vapor and Postgres

Laxman Sahni
7 min readJul 20, 2018

--

In WWDC 2015, Apple announced that Swift would be open source. Shortly after that, in December 2015, Swift’s codebase was public on GitHub.

Open sourcing the Swift codebase introduces developers to a multitude of opportunities and expand the use of Swift worldwide. With its change to Open Source, it didn’t take long before a slew of new technologies based on Swift began popping up all over the place, especially for the web. Today, the most frequently used web framework for Swift is Vapor, and it is widely considered a good choice for web development because it is fast, secure, extensible and also has integration with XCode.

In this Tutorial, we will learn the basics of how to build an web app using Swift.

System requirements

To install and run Vapor, your development environment must meet these minimum requirements:

  • Operating Systems: macOS (64-bit)
  • Disk Space: 1.17 GB (does not include disk space for IDE/tools).

Prerequisites

Xcode 9.3

Install Xcode 9.x from Mac App Store

Xcode in Mac App Store

Vapor Toolkit

The toolbox includes all of Vapor’s dependencies as well as a handy CLI tool for creating new projects.

brew install vapor/tap/vapor

Tip

If you don’t already have Homebrew installed, install it at brew.sh →

Vapor installation

Verify Installation

Double check the installation was successful by running:

vapor version
Vapor version

Creating a Project

To create a new project, you must provide Vapor with a project name. For this guide, we will call the project HelloVapor. First, navigate to a directory where you would want to create the new project, then run the following command:

vapor new HelloVapor
Vapor project

Vapor will create a project called HelloVapor in your current directory. Navigate to your new project directory.

cd HelloVapor

You should see a directory similar to the following:

Directory structure

First, Vapor creates the Package.swift file. There is no need to modify it. Then there is the Sources folder, which contains App & Run folders. The main.swift file is inside Run folder. The main.swift file is our main app file, and where we initialize our server. Vapor will run this file first.

Registering Routes In Your WebApp

Now with XCode open, go to the file Sources/App/routes.swift. There you will find methods of router.

But, what is a Route? A route is a declaration of a path that is mapped to a handler.

You will note that we already have a route declared. This route points to the root directory and loads a default welcome page created by Vapor:

/// Register your application's routes here.public func routes(_ router: Router) throws {// Basic "Hello, world!" examplerouter.get("hello") { req inreturn "Hello, world!"}// Example of configuring a controllerlet todoController = TodoController()router.get("todos", use: todoController.index)router.post("todos", use: todoController.create)router.delete("todos", Todo.parameter, use: todoController.delete)}

Generate Xcode Project

Let’s create our Xcode project. After all, what’s the advantage to building a Swift project without XCode?

Navigate to your new project directory HelloVapor. Let’s now use the Vapor Toolbox’s xcode command to generate an Xcode project. This will allow us to build and run our app from inside of Xcode, just like an iOS app.

vapor xcode

The toolbox will ask you if you’d like to open Xcode automatically, select yes.

vapor xcode command

Build & Run

You should now have Xcode open and running. Select the run scheme from the scheme menu and My Mac as the deployment target, then click the play button.

Run scheme

You should see the terminal pop up at the bottom of the screen.

Server starting on http://localhost:8080

Visit Localhost

Open your web browser, and visit localhost:8080/hello →

You should see the following page.

Hello, world!
Hello world response

Persisting Information

One of the most essential capabilities of an App is persisting information. Vapor supports some of the best persistence technologies — like MySQL, PostgreSQL, MongoDB, SQLite and Redis — through the use of providers.

The Provider protocol creates a simple and predictable way to add functionality and third party packages to your Vapor project.

In this project, we will utilize PostgreSQL, but feel free to use any other technology you may be more comfortable with.

Configuring Your PostgreSQL Server

  • PostgreSql 10.x
Postgres app

Download the installer ➜ Move to Applications folder ➜ Double Click ➜ Click “Initialize” to create a new server

Click Initialize to create a server
  • pgAdmin
pgAdmin

Download the installer ➜ Move to Applications folder ➜ Double Click

Create Your Database

Open pgAdmin 4.x

Add New Server Dialog of pgAdmin

In the Add New Server Dialog, enter a server name in the General tab, I chose “TodoApi”. In the Connection tab you can enter localhost for the hostname and type a password of your choice. For this example my password will be password. You can leave the other fields as their default values.

database server config

Link your project with PostgreSQL

So far so good, but now let’s configure the database on our Vapor project. We will have to replace FluentSQLite by FluentPostgreSQL within Package.swift:

// swift-tools-version:4.0import PackageDescriptionlet package = Package(name: "HelloVapor",dependencies: [// 💧 A server-side Swift web framework..package(url: "https://github.com/vapor/vapor.git", from: "3.0.0"),// 🖋🐘 Swift ORM (queries, models, relations, etc) built on PostgreSQL..package(url: "https://github.com/vapor/fluent-postgresql.git", from: "1.0.0-rc.4.1")  // changed],targets: [.target(name: "App", dependencies: ["FluentPostgreSQL", "Vapor"]),.target(name: "Run", dependencies: ["App"]),.testTarget(name: "AppTests", dependencies: ["App"])])

It may take a bit fetching the dependency, but when done you should have FluentPostgreSQL & PostgreSQL frameworks in Dependencies group in project structure like this:

FluentPostgreSQL, PostgreSQL frameworks

Before we can run our project we’ll have to configure PostgreSQL. Let’s go 🚀

Configure your project to use PostgreSQL

Our first step is to change everything FluentSQLite related to our new FluentPostgreSQL in our Todo model Todo.swift:

import FluentPostgreSQL // changedimport Vapor/// A single entry of a Todo list.final class Todo: PostgreSQLModel {/// The unique identifier for this `Todo`.var id: Int?/// A name describing what this `Todo` entails.var Name: String/// A bool describing if this `Todo` is completed.var IsComplete: Bool/// Creates a new `Todo`.init(id: Int? = nil, name: String, isComplete: Bool) {self.id = idself.Name = nameself.IsComplete = isComplete}}/// Allows `Todo` to be used as a dynamic migration.extension Todo: Migration { }/// Allows `Todo` to be encoded to and decoded from HTTP messages.extension Todo: Content { }/// Allows `Todo` to be used as a dynamic parameter in route definitions.extension Todo: Parameter { }

The second step before we can run our project is to register the database information within our configure.swift:

import Vaporimport FluentPostgreSQL // added/// Called before your application initializes.public func configure(_ config: inout Config, _ env: inout Environment, _ services: inout Services) throws {/// Register providers firsttry services.register(FluentPostgreSQLProvider())  // changed/// Register routes to the routerlet router = EngineRouter.default()try routes(router)services.register(router, as: Router.self)/// Register middlewarevar middlewares = MiddlewareConfig() // Create _empty_ middleware config/// middlewares.use(FileMiddleware.self) // Serves files from `Public/` directorymiddlewares.use(ErrorMiddleware.self) // Catches errors and converts to HTTP responseservices.register(middlewares)// Configure a Postgres databaselet postgresqlConfig = PostgreSQLDatabaseConfig(hostname: "127.0.0.1",port: 5432,username: "postgres",database: "TodoList",password: nil)services.register(postgresqlConfig)/// Configure migrationsvar migrations = MigrationConfig()migrations.add(model: Todo.self, database: .psql) // changedservices.register(migrations)}

If you now Cmd+R or Run we should be able to access the /todos route on http://localhost:8080/todos 😊!

make sure to select Run as a scheme next to your button before running the app

Your database should now be updated in PgAdmin. You may have to refresh the database to see the changes.

Database & Tables in PostgreSQL

Where to Go From Here?

You can perform CRUD operations on the /todos route & download the completed project using the link at the bottom of this tutorial.

Download Materials

As always, any feedback is appreciated, so feel free to comment down here or reach out on twitter — and, as always,

--

--