Skip to content

01. Actix-web CRUD Implementation

This section provides a complete, production-ready example of a CRUD (Create, Read, Update, Delete) application using Actix-web and an in-memory store.

1. Project Dependencies

Add these to your Cargo.toml:

[dependencies]
actix-web = "4.0"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
uuid = { version = "1.0", features = ["v4", "serde"] }

2. The Data Model

We’ll use serde for JSON serialization and uuid for unique identifiers.

use serde::{Deserialize, Serialize};
use uuid::Uuid;

#[derive(Serialize, Deserialize, Clone)]
pub struct Task {
    pub id: Option<Uuid>,
    pub title: String,
    pub description: String,
    pub completed: bool,
}

3. Shared Application State

In-memory state is shared across handlers using Arc and Mutex.

use std::sync::{Arc, Mutex};

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

4. CRUD Handlers

Create Task

use actix_web::{post, web, HttpResponse, Responder};

#[post("/tasks")]
async fn create_task(data: web::Data<AppState>, mut task: web::Json<Task>) -> impl Responder {
    let mut tasks = data.tasks.lock().unwrap();
    task.id = Some(Uuid::new_v4());
    tasks.push(task.into_inner());
    HttpResponse::Ok().json(tasks.last().unwrap())
}

Read All Tasks

use actix_web::{get};

#[get("/tasks")]
async fn get_tasks(data: web::Data<AppState>) -> impl Responder {
    let tasks = data.tasks.lock().unwrap();
    HttpResponse::Ok().json(&*tasks)
}

Update Task

use actix_web::{put};

#[put("/tasks/{id}")]
async fn update_task(
    data: web::Data<AppState>,
    path: web::Path<Uuid>,
    task_update: web::Json<Task>,
) -> impl Responder {
    let mut tasks = data.tasks.lock().unwrap();
    let id = path.into_inner();
    if let Some(task) = tasks.iter_mut().find(|t| t.id == Some(id)) {
        task.title = task_update.title.clone();
        task.description = task_update.description.clone();
        task.completed = task_update.completed;
        return HttpResponse::Ok().json(task);
    }
    HttpResponse::NotFound().body("Task not found")
}

Delete Task

use actix_web::{delete};

#[delete("/tasks/{id}")]
async fn delete_task(data: web::Data<AppState>, path: web::Path<Uuid>) -> impl Responder {
    let mut tasks = data.tasks.lock().unwrap();
    let id = path.into_inner();
    if let Some(pos) = tasks.iter().position(|t| t.id == Some(id)) {
        tasks.remove(pos);
        return HttpResponse::NoContent().finish();
    }
    HttpResponse::NotFound().body("Task not found")
}

5. Main Server Setup

use actix_web::{App, HttpServer};

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

    HttpServer::new(move || {
        App::new()
            .app_data(app_state.clone())
            .service(create_task)
            .service(get_tasks)
            .service(update_task)
            .service(delete_task)
    })
    .bind(("127.0.0.1", 8080))?
    .run()
    .await
}

This concludes the Rust University Curriculum. You have now learned the foundations, advanced concepts, and how to build a real-world web application.