12k
All articles

Начало работы с Loco — ответ Rust на Rails

Создайте веб-приложение на Rust с Loco — фреймворком в духе Rails. Установите CLI, сгенерируйте CRUD API и добавьте фоновый обработчик в Loco 1.2.

OpenReplay Team
OpenReplay Team
Начало работы с Loco — ответ Rust на Rails

Loco — веб-фреймворк на Rust, вдохновлённый Rails. Он объединяет маршрутизацию Axum, модели и миграции Sea-ORM, фоновые воркеры и генераторы кода под единой командой cargo loco.

Если вам доводилось тратить выходные на то, чтобы связать Axum, ORM, инструмент миграций и очередь задач, прежде чем написать хоть строчку бизнес-логики, то Loco создан как раз для того, чтобы избавить вас от этой работы. В этом руководстве мы установим Loco, создадим API-приложение, сгенерируем ресурс через scaffold и добавим фоновую задачу. Многие старые руководства написаны для версий до 1.0, поэтому все команды ниже используют CLI версии 1.x из Loco 1.2.0. Если вы только знакомитесь с языком, начните с основ Rust.

Ключевые выводы

  • Loco — веб-фреймворк на Rust, построенный по образцу Ruby on Rails. Он использует Axum для маршрутизации и Sea-ORM 2.0 для моделей и миграций.
  • CLI устанавливается командой cargo install loco. Также потребуется cargo install sea-orm-cli, но только если ваше приложение использует базу данных.
  • В Loco 1.2 команда cargo loco generate scaffold создаёт миграцию, модель, сущность, DTO и CRUD-контроллер, а затем применяет миграцию. Отдельный шаг миграции не нужен.
  • Сервер разработки нового приложения Loco слушает порт 5150.
  • Во время разработки фоновые задачи выполняются внутри процесса в режиме BackgroundAsync. В продакшене их обычно переносят в очередь на Redis, Postgres или SQLite, которую обрабатывает cargo loco start --worker.

Что такое Loco в Rust?

Loco — это фреймворк полного цикла на Rust с чётко заданными соглашениями. Он берёт на себя выбор стека, который в «голом» проекте на Axum остаётся за вами. На главной странице Loco в качестве HTTP-слоя указан Axum, а в качестве ORM — Sea-ORM 2.0. Также встроены воркеры, планировщик, отправка почты, хранилище и кэширование. Вы получаете единую структуру проекта, единую систему конфигурации и единый CLI, поэтому вам не нужно выбирать пять крейтов и писать код, связывающий их между собой. Исходный код доступен на GitHub. Loco получил первый стабильный релиз, 1.0, в июле 2026 года.

Какие идеи Rails заимствует Loco?

Loco перенимает четыре привычных для Rails подхода. Каждый проект имеет одинаковую предсказуемую структуру, генераторы пишут шаблонный код, изменения схемы проходят через версионируемые миграции, а медленные операции выносятся в фоновые задачи. Если вы знакомы с Django или Laravel, то встречали те же идеи под другими названиями.

КонцепцияЧто означаетКоманда или расположение в Loco 1.2
Соглашения важнее конфигурацииФайлы находятся там, где их ожидает фреймворкСгенерированная структура в src/ и config/
ГенераторыCLI пишет шаблонный кодcargo loco generate scaffold, model, controller, worker
МиграцииВерсионируемые изменения схемыmigration/src/, применяются автоматически при генерации
Фоновые задачиРабота выполняется вне цикла обработки запросаcargo loco generate worker, perform_later

Как установить Loco и создать приложение?

Установка Loco занимает две команды cargo, а создание приложения — ещё одну. Как отмечено в README Loco, установка sea-orm-cli нужна только в том случае, если приложение использует базу данных. В этом примере используется SQLite, поэтому она понадобится:

cargo install loco
cargo install sea-orm-cli

Далее сгенерируйте приложение. Если передать все четыре флага, мастер пропустит интерактивные вопросы, поэтому команду можно использовать в скриптах, и она всегда даёт одинаковый результат:

loco new --name tour_app --db sqlite --bg async --assets none
cd tour_app
cargo loco start

Согласно официальному руководству по созданию первого приложения, --db sqlite выбирает SQLite в качестве базы данных, --bg async запускает фоновые задачи внутри процесса, а --assets none отключает генерацию представлений, так что приложение отдаёт только JSON. Последняя строка вывода при запуске подтверждает, что сервер работает:

listening on port 5150

По умолчанию сервер разработки слушает порт 5150. В конфигурационных файлах порт задаётся через вызов get_env, который читает переменную окружения PORT, как показано в справочнике по конфигурации, так что изменить его можно там. Поскольку вы выбрали базу данных, приложение также поставляется со встроенными маршрутами аутентификации в /api/auth/*.

В старых руководствах устанавливается крейт loco-cli. В Loco 1.0 этот крейт удалён, и теперь CLI устанавливается как loco.

Как сгенерировать ресурс с помощью scaffold?

Scaffold в Loco одной командой создаёт работающий CRUD API с хранением данных в базе:

cargo loco generate scaffold posts title:string! content:text --no-auth

В Loco 1.2 команда cargo loco generate scaffold создаёт миграцию, модель и сущность Sea-ORM, типизированные DTO для запросов и ответов, а также CRUD-контроллер. Затем она применяет миграцию и заново генерирует сущности, так что отдельную команду миграции запускать не нужно.

Синтаксис полей описан в руководстве по добавлению модели. Тип, оканчивающийся на !, например title:string!, создаёт обязательный столбец. Тип без модификатора, например content:text, создаёт столбец, допускающий NULL, а ^ помечает поле как уникальное. По умолчанию сгенерированные маршруты требуют JWT, поэтому анонимный запрос вернёт 401. Флаг --no-auth делает маршруты публичными, что упрощает этот пример.

Части сгенерированного проекта, используемые в этом руководстве (структура показана не полностью):

tour_app/
├── config/development.yaml
├── migration/src/
└── src/
    ├── app.rs
    ├── controllers/posts.rs
    ├── dtos/
    ├── models/_entities/
    └── workers/

Чтобы проверить новый эндпоинт, перезапустите сервер и отправьте POST-запрос:

curl -X POST -H "Content-Type: application/json" \
  -d '{"title":"Tour post","content":"hi"}' localhost:5150/api/posts

JSON-ответ начинается с {"id":1,, после чего возвращается сохранённый пост.

Как добавить фоновую задачу в Loco?

Фоновая задача в Loco — это модуль воркера с типизированной структурой аргументов. Задача ставится в очередь с помощью perform_later. Сгенерируйте воркер:

cargo loco generate worker notifier
added: "src/workers/notifier.rs"
injected: "src/workers/mod.rs"
injected: "src/app.rs"

Как поясняется в руководстве по фоновым воркерам, генератор всегда называет структуру Worker и помещает её в отдельный модуль рядом с пустой структурой WorkerArgs, которую вы заполняете сами. Это значит, что сгенерированный воркер notifier — это workers::notifier::Worker. В файле src/workers/notifier.rs добавьте поле в WorkerArgs и замените тело perform. Метод build и остальную часть сгенерированного файла оставьте без изменений:

#[derive(Deserialize, Debug, Serialize)]
pub struct WorkerArgs {
    pub post_id: i64,
}

// inside the generated `impl BackgroundWorker<WorkerArgs> for Worker`
async fn perform(&self, args: WorkerArgs) -> Result<()> {
    println!("new post created: {}", args.post_id);
    Ok(())
}

Затем откройте src/controllers/posts.rs и добавьте следующие строки в сгенерированный обработчик create сразу после строки, которая вставляет новый пост (let item = item.insert(&ctx.db).await?;). Начиная с Loco 1.0, генерируемые первичные ключи имеют тип i64, поэтому item.id подходит для post_id без преобразования:

crate::workers::notifier::Worker::perform_later(
    &ctx,
    crate::workers::notifier::WorkerArgs { post_id: item.id },
)
.await?;

Начиная с Loco 1.0, perform_later() возвращает идентификатор задачи в виде Result<String>, как указано в примечаниях к релизу Loco 1.0. При желании его можно залогировать, чтобы позже отслеживать задачи.

В файле config/development.yaml параметр workers.mode установлен в BackgroundAsync, что означает выполнение задач как Tokio-задач внутри процесса. Режиму BackgroundAsync вообще не нужен бэкенд очереди. Для продакшена переключите workers.mode на BackgroundQueue, настройте очередь на Redis, Postgres или SQLite и обрабатывайте задачи в отдельном процессе с помощью cargo loco start --worker. Очереди на Postgres и SQLite работают с фичей worker, включённой по умолчанию, а для очереди на Redis нужна worker_redis; бэкенд выбирается в конфигурации параметром queue.kind. Код воркера и контроллера при переключении не меняется.

Кому подходит Loco?

Loco значительно ускоряет настройку бэкенда на Rust, но не устраняет издержки разработки на этом языке:

  • Время компиляции. Каждое изменение проходит через rustc, поэтому цикл «правка — перезагрузка» медленнее, чем во фреймворках на Ruby, Python или PHP.
  • Экосистема. Сторонних интеграций, плагинов и готовых ответов на вопросы гораздо меньше, чем накопилось у Rails или Django.
  • Порог входа. Сгенерированный код по-прежнему предполагает, что вы уверенно владеете концепциями владения, async и трейтами, а ошибки компилятора в обработчиках — что вы умеете их читать.

Loco хорошо подойдёт разработчикам, которые уже знают Rust и хотят получить скорость старта в стиле Rails, а также разработчикам на Rails, Django или Laravel, которые осознанно переходят на Rust. Это неудачный выбор для первого бэкенда, если вы одновременно изучаете веб-серверы и Rust. Если вы ещё решаете, стоит ли изучать Rust для веб-разработки, прочитайте статью о том, нужен ли Rust веб-разработчикам.

Заключение

Loco даёт Rust-разработчикам то же, что Rails даёт разработчикам на Ruby: единый CLI, предсказуемую структуру проекта, встроенные миграции и фоновые задачи — всё это поверх Axum и Sea-ORM. Используйте команды версии 1.x из этого руководства, а не команды до 1.0 из старых материалов. Следующий шаг — добавить второй ресурс с помощью cargo loco generate model, а затем пройти руководство по фоновым воркерам, чтобы перевести очередь с BackgroundAsync на персистентный бэкенд.

Часто задаваемые вопросы

Можно ли использовать существующие middleware и экстракторы Axum в приложении Loco?

Да. Loco по большей части представляет собой связующий код вокруг Axum, поэтому собственные экстракторы, реализующие FromRequestParts, работают в контроллерах Loco. Чтобы подключить слои Tower, например таймаут из tower-http или слой сессий, реализуйте Hooks::after_routes в src/app.rs — этот метод получает роутер Axum, уже собранный Loco.

Как перевести приложение Loco с SQLite на Postgres?

Укажите в параметре database.uri в config/development.yaml или config/production.yaml строку подключения вида postgres://. Сгенерированная конфигурация считывает это значение через get_env из переменной DATABASE_URL, поэтому можно также задать эту переменную окружения. По умолчанию Loco ожидает пользователя loco, пароль loco и базу данных, названную по имени приложения и окружения, например myapp_development. Добавление sslmode=require в URI включает TLS для Postgres без каких-либо дополнительных фич Cargo.

Как развернуть приложение Loco в продакшене?

Соберите релизный бинарник командой cargo build --release и скопируйте его на сервер вместе с папкой config/. На целевой машине не нужны ни тулчейн Rust, ни cargo. Для упаковки команда cargo loco generate deployment предлагает три варианта: docker, nginx и lambda. Вариант docker создаёт Dockerfile и .dockerignore, nginx — конфигурацию обратного прокси, а lambda — точку входа для AWS Lambda и добавляет зависимость lambda_http. Настройки продакшена хранятся в config/production.yaml.

Чем планировщик Loco отличается от фоновых воркеров?

Воркеры выполняют задачи, которые ваш код ставит в очередь через perform_later, а планировщик запускает задачи по расписанию. Задачи планировщика объявляются в YAML-конфигурации, у каждой — cron-выражение или расписание на простом английском языке. Значение run указывает на зарегистрированную задачу (task) Loco или на shell-команду, если shell равно true. Флаг --scheduler запускает планировщик вместе с сервером без отдельного процесса воркера.

DevTools for the frontend

Gain Debugging Superpowers

Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers.

Star on GitHub12k

We use cookies to improve your experience. By using our site, you accept cookies.