Rocket для Rust: полное руководство с примерами

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

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

Начать курс

Rocket для Rust: полное руководство с примерами

Что это и зачем нужна?

Rocket — это современный веб-фреймворк для языка Rust, который ставит во главу угла удобство разработки, безопасность и производительность. В отличие от многих других веб-фреймворков, Rocket использует мощную систему типов Rust для проверки корректности кода на этапе компиляции, что позволяет избежать целого класса runtime-ошибок. Он предоставляет декларативный API для маршрутизации, встроенную поддержку сериализации/десериализации через Serde, автоматическую валидацию данных из форм и URL, а также систему middleware на основе трейтов.

Зачем нужен Rocket? Если вы пишете на Rust и хотите создать веб-приложение (API, сайт, микросервис) с минимальным количеством шаблонного кода и максимальной безопасностью — Rocket идеальный выбор. Он особенно хорош для проектов, где важна надёжность: финансовые сервисы, системы управления данными, backend для мобильных приложений. Благодаря асинхронной архитектуре на основе Tokio, Rocket легко справляется с тысячами одновременных соединений.

Основные преимущества Rocket: типобезопасные маршруты (компилятор проверяет, что вы не передадите строку туда, где ожидается число), автоматическая генерация документации через Rocket.toml, встроенная поддержка WebSocket, простая работа с базами данных через Diesel или SQLx, и нулевая стоимость абстракций — все проверки выполняются на этапе компиляции, без замедления runtime.

Установка

Для работы с Rocket вам понадобится установленный Rust (рекомендуется версия 1.75+). Установка фреймворка производится через менеджер пакетов Cargo. Добавьте зависимость в файл Cargo.toml вашего проекта:

[package]
name = "my_rocket_app"
version = "0.1.0"
edition = "2021"

[dependencies]
rocket = "0.5.1"

После этого выполните команду для загрузки зависимостей:

cargo build

Для работы с JSON вам потребуется добавить Serde:

rocket = { version = "0.5.1", features = ["json"] }
serde = { version = "1.0", features = ["derive"] }

Установка завершена. Теперь вы можете создавать веб-приложения на Rust с помощью Rocket.

Быстрый старт — минимальный рабочий пример

Создайте файл src/main.rs со следующим содержимым:

#[macro_use] extern crate rocket;

#[get("/")]
fn index() -> &'static str {
    "Привет, мир Rocket!"
}

#[launch]
fn rocket() -> _ {
    rocket::build().mount("/", routes![index])
}

Запустите приложение командой cargo run. После компиляции откройте браузер и перейдите по адресу http://localhost:8000. Вы увидите сообщение "Привет, мир Rocket!". Поздравляю, ваше первое Rocket-приложение работает!

Разберём код: #[get("/")] — атрибут, указывающий, что функция обрабатывает GET-запросы к корневому пути. #[launch] — макрос, создающий точку входа. rocket::build() создаёт экземпляр приложения, а .mount() привязывает маршруты к базовому пути.

Основные методы/функции/классы

1. #[get(path)] — Обработка GET-запросов

Сигнатура: #[get("/path")] fn handler() -> T

Что делает: Атрибут, который регистрирует функцию как обработчик HTTP GET-запросов по указанному пути. Возвращаемое значение автоматически сериализуется в HTTP-ответ.

#[get("/hello")]
fn hello() -> &'static str {
    "Hello, Rocket!"
}

#[get("/user/<id>")]
fn user(id: u32) -> String {
    format!("User ID: {}", id)
}

2. #[post(path)] — Обработка POST-запросов

Сигнатура: #[post("/path", data = "<variable>")] fn handler(variable: DataType) -> T

Что делает: Атрибут для обработки POST-запросов. Параметр data указывает, какие данные ожидать в теле запроса. Rocket автоматически десериализует JSON, формы или другие форматы.

use rocket::serde::{Deserialize, json::Json};

#[derive(Deserialize)]
struct User {
    name: String,
    age: u8,
}

#[post("/user", data = "<user>")]
fn create_user(user: Json<User>) -> String {
    format!("Created user: {} ({} years old)", user.name, user.age)
}

3. rocket::build() — Создание экземпляра приложения

Сигнатура: pub fn build() -> Rocket<Build>

Что делает: Создаёт новый экземпляр Rocket-приложения в состоянии сборки. Позволяет настраивать маршруты, middleware, состояние и другие компоненты перед запуском.

#[launch]
fn rocket() -> _ {
    rocket::build()
        .mount("/api", routes![hello, create_user])
        .attach(Fairing::from(|rocket| {
            println!("Server starting...");
            rocket
        }))
}

4. .mount(base, routes) — Привязка маршрутов

Сигнатура: pub fn mount(self, base: &str, routes: Vec<Route>) -> Self

Что делает: Привязывает список маршрутов к указанному базовому пути. Все маршруты будут доступны по адресу /base/path. Позволяет группировать эндпоинты по логическим разделам.

#[get("/status")]
fn status() -> &'static str { "OK" }

#[get("/version")]
fn version() -> &'static str { "1.0.0" }

fn configure_app() -> rocket::Rocket<rocket::Build> {
    rocket::build()
        .mount("/health", routes![status, version])
        .mount("/api/v1", routes![create_user, get_user])
}

5. State<T> — Управление состоянием приложения

Сигнатура: pub struct State<'r, T: Send + Sync + 'static>(&'r T)

Что делает: Позволяет хранить и получать доступ к глобальному состоянию приложения (например, пул соединений с БД, конфигурация). Состояние должно быть потокобезопасным (Send + Sync).

use std::sync::atomic::{AtomicUsize, Ordering};

struct AppState {
    counter: AtomicUsize,
}

#[get("/count")]
fn count(state: &State<AppState>) -> String {
    let current = state.counter.fetch_add(1, Ordering::SeqCst);
    format!("Request count: {}", current + 1)
}

#[launch]
fn rocket() -> _ {
    rocket::build()
        .manage(AppState { counter: AtomicUsize::new(0) })
        .mount("/", routes![count])
}

6. Form<T> — Обработка HTML-форм

Сигнатура: pub struct Form<T>(pub T)

Что делает: Автоматически десериализует данные из URL-encoded формы (application/x-www-form-urlencoded) в структуру Rust. Поддерживает вложенные структуры и валидацию.

use rocket::form::Form;

#[derive(FromForm)]
struct LoginForm {
    username: String,
    password: String,
    remember_me: Option<bool>,
}

#[post("/login", data = "<form>")]
fn login(form: Form<LoginForm>) -> String {
    format!(
        "Login attempt: username={}, remember={}",
        form.username,
        form.remember_me.unwrap_or(false)
    )
}

7. #[catch(status)] — Обработка ошибок

Сигнатура: #[catch(status_code)] fn handler() -> T

Что делает: Регистрирует функцию-обработчик для определённого HTTP-статуса ошибки (404, 500, 422 и т.д.). Позволяет возвращать кастомные страницы ошибок или JSON-ответы.

#[catch(404)]
fn not_found() -> &'static str {
    "Страница не найдена. Проверьте URL."
}

#[catch(500)]
fn internal_error() -> rocket::response::content::Json<&'static str> {
    rocket::response::content::Json("{\"error\":\"Внутренняя ошибка сервера\"}")
}

#[launch]
fn rocket() -> _ {
    rocket::build()
        .mount("/", routes![index])
        .register("/", catchers![not_found, internal_error])
}

8. Fairing — Middleware-система

Сигнатура: pub trait Fairing: Send + Sync + 'static { ... }

Что делает: Позволяет внедрять кастомную логику на различных этапах обработки запроса (до, после, при запуске/остановке). Используется для логирования, аутентификации, CORS и других сквозных задач.

use rocket::{Rocket, Build, fairing::{Fairing, Info, Kind}};

struct RequestLogger;

#[rocket::async_trait]
impl Fairing for RequestLogger {
    fn info(&self) -> Info {
        Info {
            name: "Request Logger",
            kind: Kind::Request | Kind::Response
        }
    }

    async fn on_request(&self, request: &mut rocket::Request<'_>, _: &mut rocket::Data<'_>) {
        println!("→ {} {}", request.method(), request.uri());
    }

    async fn on_response<'r>(&self, request: &'r rocket::Request<'_>, response: &mut rocket::Response<'r>) {
        println!("← {} {}", response.status(), request.uri());
    }
}

#[launch]
fn rocket() -> _ {
    rocket::build()
        .attach(RequestLogger)
        .mount("/", routes![index])
}

9. rocket::response::content::Json — JSON-ответы

Сигнатура: pub struct Json<T>(pub T)

Что делает: Оборачивает данные в JSON-ответ с правильным Content-Type. Работает с любыми типами, реализующими Serialize из Serde. Автоматически устанавливает заголовки.

use rocket::serde::{Serialize, json::Json};

#[derive(Serialize)]
struct ApiResponse {
    success: bool,
    message: String,
    data: Option<Vec<String>>,
}

#[get("/api/data")]
fn get_data() -> Json<ApiResponse> {
    Json(ApiResponse {
        success: true,
        message: "Данные получены".to_string(),
        data: Some(vec!["item1".into(), "item2".into()]),
    })
}

10. rocket::tokio::spawn — Асинхронные задачи

Сигнатура: pub fn spawn<F>(future: F) -> JoinHandle<F::Output>

Что делает: Запускает асинхронную задачу в фоновом режиме. Используется для выполнения длительных операций (отправка email, обработка файлов) без блокировки основного потока обработки запросов.

use rocket::tokio;

#[get("/process")]
async fn process() -> &'static str {
    tokio::spawn(async {
        // Имитация длительной операции
        tokio::time::sleep(tokio::time::Duration::from_secs(5)).await;
        println!("Фоновая задача завершена");
    });
    "Задача запущена в фоне"
}

Реальный практический пример (100-200 строк кода)

Создадим полноценное REST API для управления списком задач (Todo List) с хранением в памяти. Этот пример демонстрирует: CRUD-операции, состояние приложения, обработку ошибок, JSON-сериализацию и асинхронные операции.

#[macro_use] extern crate rocket;

use rocket::serde::{Deserialize, Serialize, json::Json};
use rocket::tokio::sync::Mutex;
use std::collections::HashMap;
use std::sync::Arc;

// Типы данных
#[derive(Debug, Clone, Serialize, Deserialize)]
struct Todo {
    id: u64,
    title: String,
    completed: bool,
}

#[derive(Debug, Deserialize)]
struct CreateTodoRequest {
    title: String,
}

#[derive(Debug, Deserialize)]
struct UpdateTodoRequest {
    title: Option<String>,
    completed: Option<bool>,
}

// Состояние приложения
type TodoStore = Arc<Mutex<HashMap<u64, Todo>>>;

struct AppState {
    store: TodoStore,
    next_id: Mutex<u64>,
}

// Обработчики марш                    

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