Введение: почему REST API на Swift — это быстро и современно
Разработка мобильных приложений под iOS и macOS требует не только красивого интерфейса, но и надежного серверного бэкенда. REST API (Representational State Transfer) остается стандартом де-факто для обмена данными между клиентом и сервером. Если вы уже пишете на Swift для Apple-экосистемы, то создание API на том же языке — логичный шаг. Это позволяет переиспользовать модели данных, избегать дублирования кода и быстрее внедрять изменения.
В этой статье мы покажем, как написать полноценный REST API на Swift с использованием фреймворка Vapor — самого популярного веб-фреймворка для Swift. Вы узнаете, как настроить проект, создать маршруты, обрабатывать JSON и запустить сервер. Весь процесс займет не более 30 минут. Готовы? Поехали!
1. Подготовка окружения и установка Vapor
Прежде чем писать код, убедитесь, что у вас установлены необходимые инструменты. Для работы с Vapor потребуется Swift 5.9 или новее (рекомендуется Swift 6). Также вам понадобится терминал и редактор кода (Xcode или VS Code).
Установка Vapor Toolbox
Vapor Toolbox — это утилита командной строки, которая упрощает создание и управление проектами. Установите её через Homebrew:
brew install vapor
Если Homebrew не установлен, скачайте его с brew.sh. После установки проверьте версию:
vapor --version
Создание нового проекта
Откройте терминал и выполните команду:
vapor new MyAPI --template=api
Флаг --template=api создает базовую структуру для REST API без лишних файлов. Перейдите в папку проекта:
cd MyAPI
Теперь откройте проект в Xcode:
open Package.swift
Или используйте любой другой редактор. Готово! У вас есть чистый шаблон Vapor.
2. Базовая структура: модели, контроллеры и маршруты
Vapor использует архитектуру MVC (Model-View-Controller), адаптированную под серверную разработку. Мы создадим простое API для управления списком задач (To-Do list).
Создание модели
Модель — это структура, которая описывает данные. В папке Sources/App/Models/ создайте файл Todo.swift:
import Fluent
import Vapor
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
}
}
Мы используем Fluent — ORM от Vapor для работы с базами данных. Модель автоматически сериализуется в JSON благодаря протоколу Content.
Создание контроллера
Контроллер содержит логику обработки запросов. Создайте файл Sources/App/Controllers/TodoController.swift:
import Vapor
import Fluent
struct TodoController: RouteCollection {
func boot(routes: RoutesBuilder) throws {
let todos = routes.grouped("todos")
todos.get(use: index)
todos.post(use: create)
todos.group(":todoID") { todo in
todo.delete(use: delete)
}
}
// GET /todos — получить все задачи
func index(req: Request) async throws -> [Todo] {
try await Todo.query(on: req.db).all()
}
// POST /todos — создать задачу
func create(req: Request) async throws -> Todo {
let todo = try req.content.decode(Todo.self)
try await todo.save(on: req.db)
return todo
}
// DELETE /todos/:id — удалить задачу
func delete(req: Request) async throws -> HTTPStatus {
guard let todo = try await Todo.find(req.parameters.get("todoID"), on: req.db) else {
throw Abort(.notFound)
}
try await todo.delete(on: req.db)
return .ok
}
}
Регистрация маршрутов
Откройте файл Sources/App/routes.swift и добавьте вызов контроллера:
import Vapor
func routes(_ app: Application) throws {
try app.register(collection: TodoController())
}
Теперь ваше API имеет три эндпоинта: GET /todos, POST /todos и DELETE /todos/:id.
3. Настройка базы данных и миграции
Для хранения данных мы используем SQLite — легковесную базу, не требующую установки отдельного сервера. Vapor автоматически настраивает её в шаблоне, но нужно создать миграцию.
Создание миграции
Миграция описывает структуру таблицы. Создайте файл Sources/App/Migrations/CreateTodo.swift:
import Fluent
import Vapor
struct CreateTodo: AsyncMigration {
func prepare(on database: Database) async throws {
try await database.schema("todos")
.id()
.field("title", .string, .required)
.field("is_completed", .bool, .required)
.create()
}
func revert(on database: Database) async throws {
try await database.schema("todos").delete()
}
}
Теперь зарегистрируйте миграцию в файле Sources/App/configure.swift:
import Vapor
import Fluent
import FluentSQLiteDriver
public func configure(_ app: Application) throws {
app.databases.use(.sqlite(.file("db.sqlite")), as: .sqlite)
app.migrations.add(CreateTodo())
try app.autoMigrate().wait()
try routes(app)
}
При запуске сервера Vapor автоматически создаст таблицу todos в файле db.sqlite.
4. Запуск и тестирование API
Всё готово к запуску! Выполните в терминале:
vapor run
Сервер запустится на http://127.0.0.1:8080. Теперь протестируем эндпоинты с помощью cURL