Einleitung: Warum Rust für REST APIs?
Rust ist eine moderne systemnahe Programmiersprache, die die Leistung von C++ mit Speichersicherheit kombiniert. In den letzten Jahren ist sie zu einer beliebten Wahl für die Erstellung hochbelastbarer Webdienste geworden. Wenn Sie bereits mit Python vertraut sind und etwas Neues ausprobieren möchten, ist Rust ein ausgezeichneter nächster Schritt.
In diesem Artikel erstellen wir eine vollständige REST API zur Verwaltung einer Aufgabenliste (Todo List) in Rust unter Verwendung des Frameworks Actix-web. Der gesamte Prozess dauert nicht länger als 30 Minuten, wenn Sie der Anleitung folgen.
1. Vorbereitung der Umgebung
Rust installieren
Wenn Sie Rust noch nicht installiert haben, führen Sie den folgenden Befehl im Terminal aus (Linux/macOS):
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | shFür Windows laden Sie das Installationsprogramm von der offiziellen Website herunter.
Überprüfen Sie nach der Installation die Version:
rustc --versionProjekt erstellen
Erstellen wir ein neues Projekt mit Cargo, dem Paketmanager von Rust:
cargo new rust_todo_apicd rust_todo_apiAbhängigkeiten hinzufügen
Öffnen Sie die Datei Cargo.toml und fügen Sie die folgenden Abhängigkeiten hinzu:
[dependencies]actix-web = "4"actix-rt = "2"serde = { version = "1", features = ["derive"] }serde_json = "1"tokio = { version = "1", features = ["full"] }Speichern Sie die Datei. Cargo lädt beim ersten Build automatisch alle Bibliotheken herunter.
2. Datenmodell und Speicher erstellen
Bevor wir Endpunkte schreiben, definieren wir die Datenstruktur. Wir verwenden einen einfachen Vektor im Speicher (zur Demonstration).
Aufgabenmodell
Erstellen Sie die Datei src/models.rs:
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize, Clone)]pub struct Task { pub id: u32, pub title: String, pub completed: bool,}Globaler Speicher
In src/main.rs fügen wir einen globalen Zustand hinzu. Für die Threadsicherheit verwenden wir 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. Implementierung der CRUD-Endpunkte
Jetzt schreiben wir die wichtigsten Handler. Alle erhalten den Anwendungszustand über web::Data.
GET /tasks — alle Aufgaben abrufen
async fn get_tasks(data: web::Data<AppState>) -> impl Responder { let tasks = data.tasks.lock().unwrap(); HttpResponse::Ok().json(tasks.clone())}POST /tasks — neue Aufgabe erstellen
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} — Aufgabe nach ID abrufen
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} — Aufgabe löschen
async fn delete_task(data: web::Data<AppState>, path: web::Path<u32>) -> impl Responder { let id = path.into_inner(); l