Introduction: Why Swift for REST API?
Swift is not only a language for mobile applications. Thanks to frameworks like Vapor and Kitura, you can create full-featured REST APIs for the server side. This is especially useful if your iOS app already uses Swift: you can write both the client and server in the same language, reducing development time and simplifying code maintenance.
In this article, we will create a simple REST API in Swift using the Vapor framework — the most popular solution for server-side development in Swift. We will set up the server, add routes for CRUD operations, and test it. The entire process will take no more than 30 minutes.
Requirements: macOS or Linux, installed Swift 5.8+ (or newer), basic understanding of HTTP and JSON.
Step 1: Installing and Setting Up a Vapor Project
Vapor provides a convenient CLI tool for a quick start. Install it via Homebrew:
brew install vaporThen create a new project:
vapor new MyAPI --template=apicd MyAPIThe --template=api flag creates a scaffold with a minimal structure for a REST API. After creating the project, open it in Xcode (or any editor):
open Package.swiftThe project structure includes:
Sources/App/— main logic (routes, controllers, models).Sources/App/routes.swift— route registration.Sources/App/configure.swift— application configuration.Package.swift— dependencies (Vapor is already included).
If you are using Xcode, it will automatically download dependencies. In the terminal, run vapor build to build.
Step 2: Creating the Data Model and Database
For a REST API, we need a model. Let's create a simple Task model with fields: id, title, completed. In Vapor, models usually inherit from Model (Fluent ORM).
Create a file Sources/App/Models/Task.swift:
import Fluentimport Vapor
final class Task: Model, Content { static let schema = "tasks"
@ID(key: .id) var id: UUID?
@Field(key: "title") var title: String
@Field(key: "completed") var completed: Bool
init() {}
init(id: UUID? = nil, title: String, completed: Bool = false) { self.id = id self.title = title self.completed = completed }}Now let's create a migration for the database table. Create a file Sources/App/Migrations/CreateTask.swift:
import Fluent
struct CreateTask: Migration { func prepare(on database: Database) -> EventLoopFuture<Void> { database.schema("tasks") .id() .field("title", .string, .required) .field("completed", .bool, .required) .create() }
func revert(on database: Database) -> EventLoopFuture<Void> { database.schema("tasks").delete() }}Add the migration to configure.swift:
app.migrations.add(CreateTask())By default, Vapor uses SQLite (a file in the project folder). If you want PostgreSQL or MySQL, change the settings in configure.swift, but for a quick start, SQLite works perfectly.
Step 3: Registering REST API Routes
Now let's create a controller to handle requests. Create a file Sources/App/Controllers/TaskController.swift:
import Vaporimport Fluent
struct TaskController: RouteCollection { func boot(routes: RoutesBuilder) throws { let tasks = routes.grouped("tasks")
tasks.get(use: index) // GET /tasks tasks.post(use: create) // POST /tasks tasks.grou