Safe Rust: Build a Real Backend (Axum + SQLx)
Соберёте сервис заметок с базой данных, который проходит приёмку: создание, чтение, правка, удаление, понятные коды ошибок и ответ 503 вместо зависания при недоступной базе. Синтаксис Rust знаком, но первый же сервис спотыкается: компилятор спорит из-за владения, а дубль в базе обрывает соединение без ответа. Ставить ничего не нужно: проверка сама собирает ваш main.rs в контейнере с Rust 1.90 и поднимает рядом PostgreSQL.
Чему вы научитесь
- Писать HTTP-сервис на Axum: роутер и вложенные маршруты, экстракторы Path, Query, Json и State, коды ответов через IntoResponse, слои Tower вокруг обработчика.
- Понимать async без магии: что происходит на .await, чем spawn отличается от spawn_blocking и почему один блокирующий вызов тормозит весь рантайм Tokio.
- Работать с PostgreSQL через SQLx без ORM: пул соединений и его параметры, query_as с проверкой типов, миграции, джойны, транзакции с откатом при ошибке.
- Держать конкурентные апдейты: где теряются обновления и чем помогают блокировки строк и версии.
- Сводить ошибки в один тип: свой AppError, оператор ? через границы слоёв, «что показать клиенту» отдельно от «что записать в лог».
- Закрывать сервис: проверка токена, авторизация через middleware, хранение паролей и секретов, лимиты частоты, размера тела и времени ответа.
- Тестировать по-настоящему: чистая логика отдельно от веба, хендлеры без сети, интеграционные тесты на живой базе, двойники через трейты.
- Видеть сервис в работе: структурные логи, трассировка, метрики, раздельные /health и /ready.
- Собирать тонкий образ: многоступенчатый Dockerfile и порядок слоёв, при котором правка main.rs не пересобирает зависимости.
Что у вас будет в конце
Сервис, который можно отдать фронтенду. POST /notes создаёт заметку, PATCH меняет только присланные поля, DELETE отвечает 204, повторное чтение удалённой — 404 с машиночитаемым кодом ошибки.
Готовность сервис сообщает двумя ручками: /health отвечает, не трогая базу, а /ready делает настоящий запрос. Когда PostgreSQL остановлен, процесс жив, /ready честно отдаёт 503 через секунду, и оркестратор уводит с него трафик.
Для кого
Для тех, кто знает синтаксис Rust, но ещё не собирал из него сервис с базой, авторизацией и деплоем.
Для бэкендеров из Go, Python или Java, которым нужно понять, где владение спорит с привычным кодом и во что обходится async.
Для тех, кто уже написал первый сервис на Axum и упёрся в вопросы про слои, ошибки, транзакции и тесты на живой базе.
Что нужно знать
Базовый Rust: владение и заимствование, трейты, Result и Option. Языку курс не учит.
Начальный SQL: SELECT с условием, JOIN, представление об индексе.
HTTP на уровне пользователя чужого API: методы, коды ответов, заголовки, JSON.
Как его собираем
Сервис растёт слоями: первый хендлер и /health, роутинг и экстракторы, SQLx и миграции, свой тип ошибки, авторизация, тесты, Docker. На каждом слое ваш код компилируется и отвечает на настоящие запросы.
Ошибки разбираются на реальном выводе. Здесь .unwrap() на вставке превращает дубль в оборванное соединение: паника убивает задачу этого запроса, и клиент не получает даже 500. Правка возвращает ошибку значением и отвечает 409 по коду 23505.
Первая версия правки не собралась, и это полезный момент: E0382 поймал перемещённую строку ещё до запуска. Сообщения rustc в курсе приводятся дословно, с объяснением, от чего именно защищает компилятор.
Что он обязан выдержать
Компилируется — ещё не значит готово. Сервис обязан выдержать дубль в другом регистре, параллельные запросы с одним заголовком, кириллицу в лимите длины и чтение несуществующей записи.
Правила для такого разбора — из уроков: длину считают через chars().count(), дубль ловит ограничение UNIQUE в самой базе, клиенту отдают код ошибки без имени ограничения, для «может не найтись» берут fetch_optional.
Самое неочевидное — гонка. В шести сериях по 20 параллельных POST успешный ответ всегда один, но 4 ответа из 120 оказались 500 с текстом ошибки базы внутри.
Как принимают работу
Решение принимает автоматическая проверка, и она ищет обходы. Она пересоздаёт базу с другими данными, шлёт запрос на случайный путь, запускает сервис на случайном порту из PORT и останавливает PostgreSQL, чтобы убедиться, что /health не ходит в базу.
Если код не собирается, проверка сразу показывает текст ошибки компилятора. На картинке — две сдачи одного сервиса: первая не прошла четыре проверки по двум причинам, вторая прошла все.
Поддержка
Вы также можете задать любой вопрос по курсу у поддержки t.me/mentorix_support
Программа курса
Модулей: 7, уроков: 57. Задачи с кодом проверяются автоматически.
Введение и подготовка
- Что мы строим: REST-сервис на Rust от первого хендлера до деплоя
- Зачем backend на Rust: где он выигрывает и где мешает
- Экосистема: Tokio, Axum, Tower, SQLx и кто за что отвечает
- Асинхронность в Rust: Future, .await и почему он ничего не делает сам
- Рантайм Tokio: задачи, spawn, блокирующий код
- Cargo: профили, фичи, workspace и время сборки
- Конфигурация и переменные окружения без паник
- Первый сервис: роутер, хендлер, запуск
Архитектура приложения
- Слои: router, handler, service, repository
- Result и оператор ?: ошибки как часть сигнатуры
- Модули, видимость, mod и pub use
- Состояние приложения: State, Arc и внедрение зависимостей
- Трейты вместо интерфейсов: абстракция репозитория
- JSON: serde, DTO и почему модель БД не равна модели API
- Владение и время жизни в веб-коде: где Rust спорит с вами
- Границы модулей: что тестировать, а что скрыть
Роутинг и обработка запросов
- Маршруты в Axum: методы, вложенные роутеры, nest
- Экстракторы: Path, Query, Json, State и порядок аргументов
- Валидация входных данных и понятный отказ
- Ответы: IntoResponse, коды состояния, заголовки
- Tower и middleware: слои вокруг обработчика
- CORS, таймауты и ограничение размера тела
- Пагинация, сортировка и фильтры в API
- Версионирование и структура маршрутов под рост
База данных: PostgreSQL и SQLx
- Пул соединений: настройка и что значат его параметры
- Запросы в SQLx: query, query_as и проверка типов
- Миграции: sqlx-cli, порядок и откат
- CRUD руками: без ORM, но без боли
- Связи: один-ко-многим и джойны без сюрпризов
- Транзакции: атомарность и откат при ошибке
- Конкурентные апдейты: гонки, блокировки, версии строк
- Производительность запросов: индексы и план выполнения
Ошибки и безопасность
- Свой тип ошибки: thiserror и границы приложения
- Из ошибки в ответ: IntoResponse и коды для клиента
- Ошибки базы: что показать клиенту, а что записать в лог
- Аутентификация по токену: проверка и отказ
- Авторизация: кто и что может делать с ресурсом
- Пароли и секреты: хранение и утечки в логах
- Инъекции и валидация: где Rust помогает, а где нет
- Ограничение частоты запросов
Тестирование и устойчивость
- Юнит-тесты: чистая логика отдельно от веба
- Тесты хендлеров: запрос и ответ без сети
- Интеграционные тесты с живой базой
- Тестовые двойники: трейты вместо моков
- Конкурентность в тестах: гонки и недетерминизм
- Паники, unwrap и как сервис остаётся живым
- Краевые случаи: пустые, огромные и странные входы
- Наблюдаемость: логи, трассировка, метрики сервиса
Финальный проект: сервис заметок
- Проектирование API: ресурсы, схемы, коды ответов
- Схема базы и миграции проекта
- CRUD заметок с проверками
- Связи: пользователи, заметки, теги
- Авторизация на уровне middleware
- Поиск и постраничная выдача
- Документация API и контрактные проверки
- Docker и подготовка к деплою
- Что дальше: нагрузка, кеш, очереди
Стоимость курса: 24990 ₽
Открыть курс на Mentorix · Все курсы