Out of all of the REST API frameworks, Vapor 3 is one of the most interesting. It uses the Swift programming language, that is most commonly associated with iOS and Mac development, and uses it on the backend. In this tutorial, we’ll go over creating a REST API with Swift and Vapor 3. Check out the Github repo and some of our video courses here.

Project Setup

The first thing that we should do is make sure that Vapor 3 is installed on our system. We can do this by adding the Vapor Toolbox using Homebrew.

brew install vapor/tap/vapor

We can then create a new project using the API specific template with the command below.

vapor new todo-api --template=api

This will create a project template with a Todo model and controller already created. Instead of removing it, we’ll add to it.

Adding Vapor 3 PostgreSQL Support

The initial template comes with support for SQLite. Inside of your Package.swift file, add the dependency for PostgresSQL and remove the SQLite dependency.

.package(url: "https://github.com/vapor/fluent-postgresql.git", from: "1.0.0")

Also, make sure to make sure that Fluent the ORM for Vapor uses PostgreSQL.

.target(name: "App", dependencies: ["FluentPostgreSQL", "Vapor"]),

Inside of you Todo.swift file, you’ll see your model. import FluentPostgreSQL in order to use that DB provider for your Todo model.

import FluentPostgreSQL

Also, make sure that your model implements the import and add a finished property to make sure that the todo item can be completed.

final class Todo: PostgreSQLModel {
    /// The unique identifier for this `Todo`.
    var id: Int?

    /// A title describing what this `Todo` entails.
    var title: String

    var finished: Bool

    /// Creates a new `Todo`.
    init(id: Int? = nil, title: String, finished: Bool) {
        self.id = id
        self.title = title
        self.finished = finished

Vapor 3 PostgreSQL Migrations

For our next step, we will add our PostgreSQL config and associate it with our model. Also, make sure to import FluentPostgreSQL.

// Configure a PostgreSQL database
    let config = PostgreSQLDatabaseConfig(hostname: "localhost", port: 5432, username: "postgres", database: "SwiftTodo", password: nil, transport: .cleartext)
    let postgres = PostgreSQLDatabase(config: config)

    /// Register the configured PostgreSQL database to the database config.
    var databases = DatabasesConfig()
    databases.add(database: postgres, as: .psql)

    /// Configure migrations
    var migrations = MigrationConfig()
    migrations.add(model: Todo.self, database: .psql)

When you run ‘vapor build” you should see the migrations in the command line.

Vapor 3 Controller

Now that we have our Model created, we can now create our controller for our CRUD functions. Inside of our TodoController.swift file, make or modify the following methods.

func index(_ req: Request) throws -> Future<[Todo]> {
        return Todo.query(on: req).all()

This queries all of the Todoes from the database.

func show(_ req: Request) throws -> Future<Todo> {
        return try req.parameters.next(Todo.self)

This takes the ID parameter and gets the Todo based on the ID.

func create(_ req: Request) throws -> Future<Todo> {
        return try req.content.decode(Todo.self).flatMap(to: Todo.self) { todo in
            return todo.save(on: req)

This method creates the todo based on the parameters from your model.

func update(_ req: Request) throws -> Future<Todo> {
        return try flatMap(to: Todo.self, req.parameters.next(Todo.self), req.content.decode(Todo.self)) { todo, updatedTodo in
            todo.title = updatedTodo.title
            todo.finished = updatedTodo.finished
            return todo.save(on: req)

This tries to get the todo based on it’s ID, update the field and resave it back to the database.

func delete(_ req: Request) throws -> Future<HTTPStatus> {
        return try req.parameters.next(Todo.self).flatMap(to: Void.self) { todo in
            return todo.delete(on: req)
        }.transform(to: .ok)

This gets the todo based on its ID and deletes it from the database.

Vapor 3 Routing

Now that we have our controller created, we can add each method to the routes.swift file.

let todoController = TodoController()
    router.get("todos", use: todoController.index)
    router.get("todos", Todo.parameter, use: todoController.show)
    router.post("todos", use: todoController.create)
    router.put("todos", Todo.parameter, use: todoController.update)
    router.delete("todos", Todo.parameter, use: todoController.delete)


I’m hopeful for the future of Vapor 3 and Swift. It even offers packages specifically for JWT authentication and DB model relationships with its ORM. If you’re interested in learning more, review some of our videos.

Codebrains Newsletter

Get weekly dev news and tutorials.

Powered by ConvertKit