Introducción: ¿por qué Rust para API REST?
Rust es un lenguaje de programación de sistemas moderno que combina el rendimiento de C++ con la seguridad de la memoria. En los últimos años, se ha convertido en una opción popular para crear servicios web de alta carga. Si ya conoces Python y quieres probar algo nuevo, Rust será un excelente paso adelante.
En este artículo crearemos una API REST completa para gestionar una lista de tareas (Todo List) en Rust utilizando el framework Actix-web. Todo el proceso no tomará más de 30 minutos si sigues las instrucciones.
1. Preparación del entorno
Instalación de Rust
Si aún no tienes Rust instalado, ejecuta el siguiente comando en la terminal (Linux/macOS):
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | shPara Windows, descarga el instalador desde el sitio oficial.
Después de la instalación, verifica la versión:
rustc --versionCreación del proyecto
Crearemos un nuevo proyecto con Cargo, el gestor de paquetes de Rust:
cargo new rust_todo_apicd rust_todo_apiAdición de dependencias
Abre el archivo Cargo.toml y agrega las siguientes dependencias:
[dependencies]actix-web = "4"actix-rt = "2"serde = { version = "1", features = ["derive"] }serde_json = "1"tokio = { version = "1", features = ["full"] }Guarda el archivo. Cargo descargará automáticamente todas las librerías en la primera compilación.
2. Creación del modelo de datos y almacenamiento
Antes de escribir los endpoints, definamos la estructura de datos. Usaremos un vector simple en memoria (para demostración).
Modelo de tarea
Crea el archivo src/models.rs:
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize, Clone)]pub struct Task { pub id: u32, pub title: String, pub completed: bool,}Almacenamiento global
En src/main.rs agregaremos el estado global. Para la seguridad en hilos, usaremos 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. Implementación de endpoints CRUD
Ahora escribiremos los manejadores principales. Todos recibirán el estado de la aplicación a través de web::Data.
GET /tasks — obtener todas las tareas
async fn get_tasks(data: web::Data<AppState>) -> impl Responder { let tasks = data.tasks.lock().unwrap(); HttpResponse::Ok().json(tasks.clone())}POST /tasks — crear una nueva tarea
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} — obtener una tarea por 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} — eliminar una tarea
async fn delete_task(data: web::Data<AppState>, path: web::Path<u32>) -> impl Responder { let id = path.into_inner(); l