How to Write a REST API in Swift in 30 Minutes: A Practical Guide

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Introduction: Why Swift is Suitable for REST API?

\n\n

When it comes to server-side development, Swift is not the first language that comes to mind. However, with the emergence of the Vapor framework (and its alternative, Kitura), Swift has become a full-fledged tool for creating REST APIs. Why use Swift on the server? First, it's a single language for iOS, macOS, and the backend — you can reuse data models. Second, Swift is fast, safe, and has excellent support for asynchrony via async/await.

\n\n

In this guide, we will create a simple REST API for managing a task list (Todo list) in Swift using the Vapor framework. You will learn how to configure a server, create routes, work with JSON, and test the API. The entire process will take about 30 minutes.

\n\n

Step 1: Installing and Setting Up the Project

\n\n

Before writing code, you need to install Vapor Toolbox — a command-line utility for creating and managing Vapor projects.

\n\n

Installing Vapor Toolbox

\n

Open the terminal and run:

\n
brew install vapor
\n

If you don't have Homebrew, install it from brew.sh.

\n\n

Creating a New Project

\n

Let's create a new project named TodoAPI:

\n
vapor new TodoAPI -n\ncd TodoAPI
\n

The -n flag means "no example" — we will get a clean template.

\n\n

Starting the Server

\n

Open the project in Xcode:

\n
open Package.swift
\n

Select the Run scheme and press Cmd+R. After a few seconds, the server will start at http://127.0.0.1:8080. Open your browser — you should see a welcome message from Vapor.

\n\n

Step 2: Creating the Data Model

\n\n

Our API will manage tasks. Each task has an ID, a title, and a completion status (completed/not completed).

\n\n

Let's create the Todo model. In Vapor, models are regular structures that conform to the Content protocol (for JSON serialization) and Codable.

\n\n

Create the file Sources/App/Models/Todo.swift:

\n
import Vapor\n\nstruct Todo: Content, Codable {\n    var id: UUID?\n    var title: String\n    var isCompleted: Bool\n    \n    init(id: UUID? = nil, title: String, isCompleted: Bool = false) {\n        self.id = id\n        self.title = title\n        self.isCompleted = isCompleted\n    }\n}
\n\n

Note: id is an optional UUID. We will generate it on the server when creating a task.

\n\n

Step 3: Creating the Store and Controller

\n\n

For simplicity, we will store tasks in memory (in an array). In a real project, you would use a database (Fluent ORM), but for a 30-minute demo, this is overkill.

\n\n

In-Memory Store

\n

Create the file Sources/App/Controllers/TodoStore.swift:

\n
import Vapor\n\nfinal class TodoStore {\n    private var todos: [Todo] = []\n    private let lock = NSLock()\n    \n    func getAll() -> [Todo] {\n        lock.lock()\n        defer { lock.unlock() }\n        return todos\n    }\n    \n    func get(id: UUID) -> Todo? {\n        lock.lock()\n        defer { lock.unlock() }\n        return todos.first { $0.id == id }\n    }\n    \n    func create(_ todo: inout Todo) -> Todo {\n        lock.lock()\n        defer { lock.unlock() }\n        todo.id = UUID()\n        todos.append(todo)\n        return todo\n    }\n    \n    func update(id: UUID, with updatedTodo: Todo) -> Todo? {\n        lock.lock()\n        defer { lock.unlock() }\n        guard let index = todos.firstIndex(where: { $0.id == id }) else { return nil }\n        var mutableTodo = updatedTodo\n        mutableTodo.id = id\n        todos[index] = mutableTodo\n        return mutableTodo\n    }\n    \n    func delete(id: UUID) ->                

Blogs

Book Recommendations