Как написать REST API на Rust за 30 минут: для начинающих

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

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

Начать курс

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

Rust — это современный системный язык программирования, который сочетает в себе производительность C++ и безопасность памяти. В последние годы он стал популярным выбором для создания высоконагруженных веб-сервисов. Если вы уже знакомы с Python и хотите попробовать что-то новое, Rust станет отличным шагом вперёд.

В этой статье мы создадим полноценный REST API для управления списком задач (Todo List) на Rust с использованием фреймворка Actix-web. Весь процесс займёт не более 30 минут, если следовать инструкции.

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

Установка Rust

Если у вас ещё не установлен Rust, выполните команду в терминале (Linux/macOS):

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

Для Windows скачайте установщик с официального сайта.

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

rustc --version

Создание проекта

Создадим новый проект с помощью Cargo — менеджера пакетов Rust:

cargo new rust_todo_api
cd rust_todo_api

Добавление зависимостей

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

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

Сохраните файл. Cargo автоматически загрузит все библиотеки при первой сборке.

2. Создание модели данных и хранилища

Прежде чем писать эндпоинты, определим структуру данных. Мы будем использовать простой вектор в памяти (для демонстрации).

Модель задачи

Создайте файл src/models.rs:

use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Task {
    pub id: u32,
    pub title: String,
    pub completed: bool,
}

Глобальное хранилище

В src/main.rs добавим глобальное состояние. Для потокобезопасности используем Mutex:

use std::sync::Mutex;
use actix_web::{web, App, HttpServer, HttpResponse, HttpRequest, Responder};
use models::Task;

mod models;

struct AppState {
    tasks: Mutex<Vec<Task>>,
    next_id: Mutex<u32>,
}

3. Реализация CRUD-эндпоинтов

Теперь напишем основные обработчики. Все они будут принимать состояние приложения через web::Data.

GET /tasks — получение всех задач

async fn get_tasks(data: web::Data<AppState>) -> impl Responder {
    let tasks = data.tasks.lock().unwrap();
    HttpResponse::Ok().json(tasks.clone())
}

POST /tasks — создание новой задачи

async fn create_task(data: web::Data<AppState>, body: web::Json<Task>) -> impl Responder {
    let mut tasks = data.tasks.lock().unwrap();
    let mut next_id = data.next_id.lock().unwrap();
    let new_task = Task {
        id: *next_id,
        title: body.title.clone(),
        completed: false,
    };
    tasks.push(new_task.clone());
    *next_id += 1;
    HttpResponse::Created().json(new_task)
}

GET /tasks/{id} — получение задачи по ID

async fn get_task(data: web::Data<AppState>, path: web::Path<u32>) -> impl Responder {
    let id = path.into_inner();
    let tasks = data.tasks.lock().unwrap();
    match tasks.iter().find(|t| t.id == id) {
        Some(task) => HttpResponse::Ok().json(task),
        None => HttpResponse::NotFound().json("Task not found"),
    }
}

DELETE /tasks/{id} — удаление задачи

async fn delete_task(data: web::Data<AppState>, path: web::Path<u32>) -> impl Responder {
    let id = path.into_inner();
    let mut tasks = data.tasks.lock().unwrap();
    if let Some(pos) = tasks.iter().position(|t| t.id == id) {
        tasks.remove(pos);
        HttpResponse::Ok().json("Task deleted")
    } else {
        HttpResponse::NotFound().json("Task not found")
    }
}

4. Настройка маршрутов и запуск сервера

Вернёмся в main.rs и соберём всё вместе:

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    let app_state = web::Data::new(AppState {
        tasks: Mutex::new(vec![]),
        next_id: Mutex::new(1),
    });

    HttpServer::new(move || {
        App::new()
            .app_data(app_state.clone())
            .route("/tasks", web::get().to(get_tasks))
            .route("/tasks", web::post().to(create_task))
            .route("/tasks/{id}", web::get().to(get_task))
            .route("/tasks/{id}", web::delete().to(delete_task))
    })
    .bind("127.0.0.1:8080")?
    .run()
    .await
}

Запуск и тестирование

Выполните в терминале:

cargo run

Сервер запустится на http://127.0.0.1:8080. Протестируйте API с помощью curl:

# Создать задачу
curl -X POST http://127.0.0.1:8080/tasks \
  -H "Content-Type: application/json" \
  -d '{"title": "Изучить Rust"}'

# Получить все задачи
curl http://127.0.0.1:8080/tasks

# Получить задачу по ID
curl http://127.0.0.1:8080/tasks/0

# Удалить задачу
curl -X DELETE http://127.0.0.1:8080/tasks/0

Заключение

Мы создали работающий REST API на Rust всего за несколько минут. Конечно, в реальном проекте потребуется подключение к базе данных, обработка ошибок, логирование и тесты. Но основа готова!

Rust с Actix-web даёт невероятную производительность и безопасность. Если вы хотите углубиться, рекомен

Блоги

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