あっぽログ
← 記事一覧に戻る

RustでActix-webを使ったREST API入門:CRUDエンドポイントを実装する

Actix-webとは?

Actix-webは、Rustで書かれた高性能なWebフレームワークです。TechEmpower Framework Benchmarksでも上位に位置する非常に高速なフレームワークで、本番環境での利用実績も豊富です。

この記事では、Actix-webを使って基本的なREST APIを構築します。インメモリのデータ(Todoリスト)を題材にして、**CRUD(Create / Read / Update / Delete)**の4つの操作を実装していきます。


プロジェクトのセットアップ

まず新しいCargoプロジェクトを作成します。

cargo new actix-todo-api
cd actix-todo-api

Cargo.toml に必要な依存関係を追加します。

[dependencies]
actix-web = "4"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
tokio = { version = "1", features = ["full"] }
uuid = { version = "1", features = ["v4"] }
  • serde / serde_json:JSONのシリアライズ・デシリアライズ
  • uuid:ユニークなIDの生成

データ構造の定義

src/main.rs にTodoアイテムの構造体を定義します。

use actix_web::{web, App, HttpServer, HttpResponse, Responder};
use serde::{Deserialize, Serialize};
use std::sync::Mutex;
use uuid::Uuid;

#[derive(Debug, Clone, Serialize, Deserialize)]
struct Todo {
    id: String,
    title: String,
    done: bool,
}

#[derive(Deserialize)]
struct CreateTodo {
    title: String,
}

#[derive(Deserialize)]
struct UpdateTodo {
    title: Option<String>,
    done: Option<bool>,
}

// アプリケーション全体で共有する状態
struct AppState {
    todos: Mutex<Vec<Todo>>,
}

Mutex<Vec<Todo>> を使って、複数のリクエストが同時にデータにアクセスしても安全なようにスレッドセーフな共有状態を定義しています。


CRUDハンドラの実装

GET /todos ─ 一覧取得

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

POST /todos ─ 新規作成

async fn create_todo(
    data: web::Data<AppState>,
    body: web::Json<CreateTodo>,
) -> impl Responder {
    let mut todos = data.todos.lock().unwrap();
    let new_todo = Todo {
        id: Uuid::new_v4().to_string(),
        title: body.title.clone(),
        done: false,
    };
    todos.push(new_todo.clone());
    HttpResponse::Created().json(new_todo)
}

web::Json<CreateTodo> でリクエストボディを自動的にデシリアライズしてくれます。

PUT /todos/ ─ 更新

async fn update_todo(
    data: web::Data<AppState>,
    path: web::Path<String>,
    body: web::Json<UpdateTodo>,
) -> impl Responder {
    let id = path.into_inner();
    let mut todos = data.todos.lock().unwrap();

    if let Some(todo) = todos.iter_mut().find(|t| t.id == id) {
        if let Some(title) = &body.title {
            todo.title = title.clone();
        }
        if let Some(done) = body.done {
            todo.done = done;
        }
        HttpResponse::Ok().json(todo.clone())
    } else {
        HttpResponse::NotFound().body("Todo not found")
    }
}

web::Path<String> でURLパスのパラメータを受け取ります。find でIDが一致するTodoを探し、存在すれば更新・なければ404を返します。

DELETE /todos/ ─ 削除

async fn delete_todo(
    data: web::Data<AppState>,
    path: web::Path<String>,
) -> impl Responder {
    let id = path.into_inner();
    let mut todos = data.todos.lock().unwrap();
    let before_len = todos.len();
    todos.retain(|t| t.id != id);

    if todos.len() < before_len {
        HttpResponse::NoContent().finish()
    } else {
        HttpResponse::NotFound().body("Todo not found")
    }
}

retain を使って、対象のIDを持つ要素を取り除きます。


ルーティングとサーバーの起動

最後に main 関数でルーティングを設定し、サーバーを起動します。

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

    HttpServer::new(move || {
        App::new()
            .app_data(state.clone())
            .route("/todos", web::get().to(get_todos))
            .route("/todos", web::post().to(create_todo))
            .route("/todos/{id}", web::put().to(update_todo))
            .route("/todos/{id}", web::delete().to(delete_todo))
    })
    .bind("127.0.0.1:8080")?
    .run()
    .await
}

動作確認

サーバーを起動します。

cargo run

curlでAPIを試してみましょう。

# Todo作成
curl -X POST http://localhost:8080/todos \
  -H "Content-Type: application/json" \
  -d '{"title": "Rustを学ぶ"}'

# 一覧取得
curl http://localhost:8080/todos

# 更新({id}は実際のIDに置き換え)
curl -X PUT http://localhost:8080/todos/{id} \
  -H "Content-Type: application/json" \
  -d '{"done": true}'

# 削除
curl -X DELETE http://localhost:8080/todos/{id}

まとめ

この記事では、Actix-webを使ってREST APIのCRUDエンドポイントを実装しました。

操作メソッドパス
一覧取得GET/todos
新規作成POST/todos
更新PUT/todos/
削除DELETE/todos/

Actix-webは非同期処理を活かした高速なフレームワークです。web::Data による状態共有、web::Json によるボディのデシリアライズなど、実用的な機能が揃っています。次のステップとして、**データベース(PostgreSQL + SQLx)**との連携に挑戦してみてください!

← 記事一覧に戻る