Как написать REST API на Rust за 30 минут: практическое руководство

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

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

Начать курс

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

Rust — это современный системный язык программирования, который сочетает в себе производительность C/C++ и безопасность памяти без сборщика мусора. Для создания REST API Rust предлагает несколько мощных фреймворков, и Actix-web — один из самых популярных. В этом руководстве мы шаг за шагом создадим полноценный REST API на Rust за 30 минут. Вы увидите, как быстро можно начать, даже если вы новичок в Rust.

Подготовка окружения

Прежде чем писать код, убедитесь, что у вас установлен Rust. Если нет — выполните команду:

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

После установки проверьте версию:

rustc --version

Теперь создайте новый проект:

cargo new rust_rest_api
cd rust_rest_api

Откройте файл Cargo.toml и добавьте зависимости:

[dependencies]
actix-web = "4"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
tokio = { version = "1", features = ["full"] }

Запустите cargo build, чтобы установить все пакеты. Это займёт 1–2 минуты.

Создание базового REST API на Rust

Начнём с простого эндпоинта, который возвращает приветствие. Откройте src/main.rs и напишите:

use actix_web::{web, App, HttpServer, Responder};

async fn hello() -> impl Responder {
    "Привет, мир! Это REST API на Rust!"
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    println!("Сервер запущен на http://127.0.0.1:8080");
    HttpServer::new(|| {
        App::new()
            .route("/", web::get().to(hello))
    })
    .bind("127.0.0.1:8080")?
    .run()
    .await
}

Запустите сервер командой cargo run и откройте в браузере http://127.0.0.1:8080. Вы увидите наше приветствие. Это основа любого REST API на Rust.

Добавление структуры данных и JSON

Настоящее REST API работает с JSON. Создадим модель пользователя и эндпоинт для его получения:

use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize)]
struct User {
    id: u32,
    name: String,
    email: String,
}

async fn get_user() -> impl Responder {
    let user = User {
        id: 1,
        name: "Иван Петров".to_string(),
        email: "ivan@example.com".to_string(),
    };
    web::Json(user)
}

// В main() добавьте новый маршрут:
// .route("/user", web::get().to(get_user))

Теперь по адресу /user вы получите JSON-объект. Это ключевой момент: Rust автоматически сериализует структуру в JSON благодаря serde.

Работа с параметрами запроса и POST-запросами

Настоящее API должно обрабатывать разные HTTP-методы и параметры. Добавим эндпоинт для создания пользователя через POST:

use actix_web::web::Json;

async fn create_user(user: Json<User>) -> impl Responder {
    let new_user = user.into_inner();
    println!("Создан пользователь: {} ({})", new_user.name, new_user.email);
    web::Json(new_user)
}

// В main():
// .route("/user", web::post().to(create_user))

Теперь можно отправить POST-запрос с телом JSON, например, через curl:

curl -X POST http://127.0.0.1:8080/user \
  -H "Content-Type: application/json" \
  -d '{"id":2,"name":"Мария Смирнова","email":"maria@example.com"}'

Сервер вернёт тот же объект, подтверждая создание. Это основа для CRUD-операций.

Обработка параметров пути и строки запроса

Добавим эндпоинт для получения пользователя по ID через параметр пути:

use actix_web::web::Path;

async fn get_user_by_id(path: Path<u32>) -> impl Responder {
    let user_id = path.into_inner();
    // В реальном приложении здесь был бы запрос к БД
    let user = User {
        id: user_id,
        name: format!("Пользователь {}", user_id),
        email: format!("user{}@example.com", user_id),
    };
    web::Json(user)
}

// В main():
// .route("/user/{id}", web::get().to(get_user_by_id))

Теперь http://127.0.0.1:8080/user/42 вернёт пользователя с ID 42. Для обработки query-параметров используйте web::Query:

use actix_web::web::Query;

#[derive(Deserialize)]
struct UserQuery {
    name: Option<String>,
    limit: Option<u32>,
}

async fn search_users(query: Query<UserQuery>) -> impl Responder {
    let name = query.name.clone().unwrap_or_default();
    let limit = query.limit.unwrap_or(10);
    web::Json(format!("Поиск пользователей: имя={}, лимит={}", name, limit))
}

// В main():
// .route("/users/search", web::get().to(search_users))

Добавление CORS и обработка ошибок

Для работы с фронтендом нужно настроить CORS. Добавьте в Cargo.toml:

actix-cors = "0.7"

И обновите main.rs:

use actix_cors::Cors;

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    HttpServer::new(|| {
        let cors = Cors::default()
            .allow_any_origin()
            .allow_any_method()
            .allow_any_header();
        
        App::new()
            .wrap(cors)
            .route("/", web::get().to(hello))
            .route("/user", web::get().to(get_user))
            .route("/user", web::post().to(create_user))
            .route("/user/{id}", web::get().to(get_user_by_id))
            .route("/users/search", web::get().to(search_users))
    })
    .bind("127.0.0.1:8080")?
    .run()
    .await
}

Для обработки ошибок используйте Http

Блоги

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