Как написать REST API на Swift за 30 минут

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Введение: почему Swift для REST API?

Swift — это не только язык для мобильных приложений. Благодаря фреймворкам, таким как Vapor и Kitura, вы можете создавать полноценные REST API для серверной части. Это особенно полезно, если ваше iOS-приложение уже использует Swift: вы можете писать и клиент, и сервер на одном языке, сокращая время разработки и упрощая поддержку кода.

В этой статье мы создадим простой REST API на Swift с помощью фреймворка Vapor — самого популярного решения для серверной разработки на Swift. Мы настроим сервер, добавим маршруты для CRUD-операций и протестируем его. Весь процесс займёт не более 30 минут.

Требования: macOS или Linux, установленный Swift 5.8+ (или новее), базовое понимание HTTP и JSON.

Шаг 1: Установка и настройка проекта Vapor

Vapor предоставляет удобный CLI-инструмент для быстрого старта. Установите его через Homebrew:

brew install vapor

Затем создайте новый проект:

vapor new MyAPI --template=api
cd MyAPI

Флаг --template=api создаёт заготовку с минимальной структурой для REST API. После создания проекта откройте его в Xcode (или любом редакторе):

open Package.swift

Структура проекта включает:

  • Sources/App/ — основная логика (маршруты, контроллеры, модели).
  • Sources/App/routes.swift — регистрация маршрутов.
  • Sources/App/configure.swift — конфигурация приложения.
  • Package.swift — зависимости (Vapor уже включён).

Если вы используете Xcode, он автоматически загрузит зависимости. В терминале выполните vapor build для сборки.

Шаг 2: Создание модели данных и базы

Для REST API нам нужна модель. Создадим простую модель Task (задача) с полями: id, title, completed. В Vapor модели обычно наследуются от Model (Fluent ORM).

Создайте файл Sources/App/Models/Task.swift:

import Fluent
import 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
    }
}

Теперь создадим миграцию для таблицы в базе данных. Создайте файл 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()
    }
}

Добавьте миграцию в configure.swift:

app.migrations.add(CreateTask())

По умолчанию Vapor использует SQLite (файл в папке проекта). Если хотите PostgreSQL или MySQL — измените настройки в configure.swift, но для быстрого старта SQLite отлично подходит.

Шаг 3: Регистрация маршрутов REST API

Теперь создадим контроллер для обработки запросов. Создайте файл Sources/App/Controllers/TaskController.swift:

import Vapor
import 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.group(":id") { task in
            task.get(use: show)       // GET /tasks/:id
            task.put(use: update)     // PUT /tasks/:id
            task.delete(use: delete)  // DELETE /tasks/:id
        }
    }

    // GET /tasks — получить все задачи
    func index(req: Request) async throws -> [Task] {
        try await Task.query(on: req.db).all()
    }

    // POST /tasks — создать задачу
    func create(req: Request) async throws -> Task {
        let task = try req.content.decode(Task.self)
        try await task.save(on: req.db)
        return task
    }

    // GET /tasks/:id — получить задачу по ID
    func show(req: Request) async throws -> Task {
        guard let task = try await Task.find(req.parameters.get("id"), on: req.db) else {
            throw Abort(.notFound)
        }
        return task
    }

    // PUT /tasks/:id — обновить задачу
    func update(req: Request) async throws -> Task {
        guard let task = try await Task.find(req.parameters.get("id"), on: req.db) else {
            throw Abort(.notFound)
        }
        let updatedTask = try req.content.decode(Task.self)
        task.title = updatedTask.title
        task.completed = updatedTask.completed
        try await task.save(on: req.db)
        return task
    }

    // DELETE /tasks/:id — удалить задачу
    func delete(req: Request) async throws -> HTTPStatus {
        guard let task = try await Task.find(req.parameters.get("id"), on: req.db) else {
            throw Abort(.notFound)
        }
        try await task.delete(on: req.db)
        return .ok
    }
}

Зарегистрируйте контроллер в routes.swift:

import Vapor

func routes(_ app: Application) throws {
    try app.register(collection: TaskController())
}

Теперь у нас есть полноценный REST API с поддержкой CRUD. Обратите внимание на использование async/await — Swift 5.5+ делает код чистым и безопасным.

Шаг 4: Запуск и тестирование API

Запустите сервер:

vapor run

Сервер будет доступен по адресу http://127.0.0.1:8080. Протестируем API с помощью curl или Postman:

  1. Создать задачу (POST):
    curl -X POST http://127.0.0.1:8080/tasks \
    -H "Content-Type: application/json" \
    -d '                

Блоги

Рекомендаций по книгам