Введение: почему 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 даёт невероятную производительность и безопасность. Если вы хотите углубиться, рекомен