返回文章列表

使用 Actix-web 實作課程管理 CRUD API

本文為一份完整的後端教學,指導如何使用 Actix-web 框架,圍繞「課程」資源設計並實現一個完整的 CRUD (建立、讀取、更新、刪除) RESTful API。內容涵蓋了路由設計、模組化 handler、資料模型定義以及 API 測試等核心環節。

Web 開發 後端開發

在建構任何線上平台時,對核心資源的管理功能都是不可或缺的。接續前文的使用者註冊與登入功能,本文將深入探討如何為一個線上教學平台,設計並實現一套完整的課程管理 (CRUD - Create, Read, Update, Delete) RESTful API。我們將遵循良好的軟體工程實踐,將相關的 handler 組織到獨立的模組中,並為每個功能設計清晰的 API 端點。

步驟一:程式碼組織與模組化

隨著應用功能的增加,將所有 handler 放在單一檔案中會變得難以維護。一個良好的實踐是根據功能領域將程式碼模組化。

  1. 建立 handler 模組: 在 src/ 目錄下建立 handler/ 資料夾。
  2. 劃分功能模組:
    • 將原有的註冊、登入相關 handler 移至 src/handler/auth.rs
    • 建立一個新的 src/handler/course.rs 檔案,專門用來存放課程管理的 handler。
  3. 宣告模組: 在 src/handler/mod.rs 中宣告這些子模組,以便外部可以存取。
    // src/handler/mod.rs
    pub mod auth;
    pub mod course;
    

步驟二:課程管理 API 路由設計

我們將所有與課程相關的 API 端點都歸納在 /courses 這個範疇 (scope) 之下,這有助於保持 API 的一致性與可讀性。

src/routes.rs 中,我們定義課程管理的路由設定:

// src/routes.rs
use crate::handler::course::{handle_delete_course, handle_insert_course, handle_update_course};
use actix_web::web;

pub fn course_routes(cfg: &mut web::ServiceConfig) {
    cfg.service(
        web::scope("/courses")
            .route("/{tutor_id}", web::post().to(handle_insert_course))
            .route("/{tutor_id}/{course_id}", web::put().to(handle_update_course))
            .route("/{tutor_id}/{course_id}", web::delete().to(handle_delete_course))
    );
}

路由設計解說

  • POST /courses/{tutor_id}: 為指定的導師新增一門課程。
  • PUT /courses/{tutor_id}/{course_id}: 更新指定導師的某一門特定課程。
  • DELETE /courses/{tutor_id}/{course_id}: 刪除指定導師的某一門特定課程。

最後,在 src/main.rsApp 設定中,載入這個路由組態:

// 在 main.rs 的 HttpServer::new(...) 中
.configure(course_routes) // 載入課程路由
.configure(auth_routes)   // 載入認證路由

步驟三:資料模型定義

為了處理課程資料的傳遞,我們需要定義相應的 Rust 結構體。

src/models.rs 中定義:

// src/models.rs
use serde::{Deserialize, Serialize};

// 用於接收新增課程請求的資料結構
#[derive(Deserialize, Debug)]
pub struct NewCourse {
    pub course_name: String,
    pub course_description: Option<String>,
    // ... 其他課程相關欄位
}

// 用於接收更新課程請求的資料結構
#[derive(Deserialize, Debug)]
pub struct UpdateCourse {
    pub course_name: Option<String>,
    pub course_description: Option<String>,
    // ... 其他可選的更新欄位
}

// 用於回傳給客戶端的課程資料結構
#[derive(Serialize, Debug)]
pub struct CourseResponse {
    pub course_id: i32,
    pub tutor_id: i32,
    pub course_name: String,
    // ... 其他欄位
}

步驟四:實現課程管理 Handlers

現在,我們在 src/handler/course.rs 中為每個路由編寫對應的 handler 存根 (stub)。在實際開發中,這些 handler 內部會呼叫資料庫存取層的函式來完成操作。

// src/handler/course.rs
use actix_web::{web, Error, HttpResponse};
use crate::state::AppState;
use crate::models::{NewCourse, UpdateCourse};

// POST /courses/{tutor_id}
pub async fn handle_insert_course(
    _app_state: web::Data<AppState>,
    _tutor_id: web::Path<i32>,
    _new_course: web::Json<NewCourse>,
) -> Result<HttpResponse, Error> {
    // TODO: 呼叫資料庫函式,將 _new_course 存入資料庫
    println!("Received new course request");
    Ok(HttpResponse::Ok().body("成功新增課程"))
}

// PUT /courses/{tutor_id}/{course_id}
pub async fn handle_update_course(
    _app_state: web::Data<AppState>,
    _path: web::Path<(i32, i32)>,
    _update_course: web::Json<UpdateCourse>,
) -> Result<HttpResponse, Error> {
    // TODO: 呼叫資料庫函式,更新對應的課程
    Ok(HttpResponse::Ok().body("成功更新課程"))
}

// DELETE /courses/{tutor_id}/{course_id}
pub async fn handle_delete_course(
    _app_state: web::Data<AppState>,
    _path: web::Path<(i32, i32)>,
) -> Result<HttpResponse, Error> {
    // TODO: 呼叫資料庫函式,刪除對應的課程
    Ok(HttpResponse::Ok().body("成功刪除課程"))
}

圖表解說:課程管理 API 處理流程

此活動圖展示了從使用者登入到管理(新增、更新、刪除)課程的完整操作流程。

@startuml
!theme _none_
skinparam dpi auto
skinparam defaultFontName "Microsoft JhengHei UI"
skinparam minClassWidth 100
skinparam defaultFontSize 16
title 課程管理活動圖

start
:使用者登入;
if (登入成功?) then (yes)
  :進入課程管理頁面;
  partition 課程操作 {
    fork
      :<b>新增課程</b>\n(POST /courses/{tutor_id});
    fork again
      :<b>更新課程</b>\n(PUT /courses/{tutor_id}/{course_id});
    fork again
      :<b>刪除課程</b>\n(DELETE /courses/{tutor_id}/{course_id});
    end fork
  }
  :API Handler 呼叫資料庫服務;
  :資料庫執行操作;
  :回傳操作結果;
else (no)
  :顯示錯誤訊息;
endif
stop

@enduml

步驟五:測試 API 端點

在啟動伺服器 (cargo run) 後,我們可以使用 curl 等工具來測試我們新建立的 API 端點是否正常運作。

# 測試新增課程
curl -X POST -H "Content-Type: application/json" \
     -d '{"course_name":"Rust入門","course_description":"基礎教學"}' \
     localhost:8080/courses/1

# 測試更新課程
curl -X PUT -H "Content-Type: application/json" \
     -d '{"course_name":"Rust進階"}' \
     localhost:8080/courses/1/1

# 測試刪除課程
curl -X DELETE localhost:8080/courses/1/1

執行這些指令後,您應該能在伺服器的控制台中看到對應的 “Got … request” 訊息,證明我們的路由和 handler 已經成功設定。接下來的工作就是填充這些 handler 的內部邏輯,與資料庫進行真實的互動。