How to Write a REST API in Swift in 30 Minutes: For Beginners
Swift is not only a language for creating mobile applications for iOS and macOS. With the advent of the Vapor framework, server-side development in Swift has become accessible and convenient. In this article, we will show you how to write a simple REST API in Swift in literally 30 minutes. You will learn the basic principles of working with Vapor, how to create routes, handle requests, and return JSON responses.
This guide is perfect for beginners who are already familiar with the basics of Swift but have never written server-side code. We will break down the process step by step, with code examples and explanations.
What is a REST API and Why Do You Need It?
REST (Representational State Transfer) is an architectural style for interaction between components of a distributed application over a network. A REST API allows client applications (e.g., an iOS app) to receive and send data to a server via HTTP requests.
The main HTTP methods used in REST are:
- GET — retrieving data
- POST — creating a new resource
- PUT — updating an existing resource
- DELETE — deleting a resource
For our example, we will create a simple API for managing a to-do list (Todo List). It will support all four basic CRUD operations (Create, Read, Update, Delete).
Installing Vapor and Creating a Project
Vapor is the most popular web framework for Swift. To get started, install the Vapor Toolbox via Homebrew:
brew install vaporAfter installation, create a new project:
vapor new TodoAPIcd TodoAPIThis command will create a project structure with a pre-configured server. Open the project in Xcode:
open Package.swiftIn Xcode, you will see the standard Vapor project structure. The main code is located in the Sources/App folder.
Creating the Data Model
To work with tasks, we need a model. Create a file Todo.swift in the Sources/App/Models folder:
import Vaporimport Fluent
final class Todo: Model, Content { static let schema = "todos" @ID(key: .id) var id: UUID? @Field(key: "title") var title: String @Field(key: "is_completed") var isCompleted: Bool init() {} init(id: UUID? = nil, title: String, isCompleted: Bool = false) { self.id = id self.title = title self.isCompleted = isCompleted }}We use Fluent — an ORM for Swift that works with databases. In our example, we will use SQLite for simplicity. Note the Content protocol — it allows the model to be automatically encoded/decoded into JSON.
Setting Up Migration and Database
Now let's create a migration for our model. Add a file CreateTodo.swift in the Sources/App/Migrations folder:
import Fluent
struct CreateTodo: Migration { func prepare(on database: Database) -> EventLoopFuture<Void> { return database.schema("todos") .id() .field("title", .string, .required) .field("is_completed", .bool, .required) .create() } func revert(on database: Database) -> EventLoopFuture<Void> { return database.schema("todos").delete() }}In the configure.swift file, add the database and migration registration:
import Fluentimport FluentSQLiteDriver
public func configure(_ app: Application) throws { app.databases.use(.sqlite(.file("db.sqlite")), as: .sqlite) app.migrations.add(CreateTodo())