在撰寫非同步 Rust 專案的這些年裡,持續關注相關工具與函式庫的演進一直是重要的學習過程。這些變化大多是正面的,特別是 Tokio 及其相關專案的進展令人印象深刻。從最初的實驗性功能到現在的成熟生態系統,Rust 在 Web 開發領域的地位日益穩固。

Rust Web 框架生態系統概覽

選擇適合的 Web 框架是開發高效能服務的關鍵決策。Rust 生態系統提供了多個成熟的 Web 框架,各有特色與適用場景。理解這些框架的設計理念與技術特性,能夠幫助我們做出明智的技術選擇。

axum 框架的設計哲學與優勢

對於開發網路服務,axum 框架是個極佳選擇,它是 Tokio 專案的一部分。axum 框架相對精簡但功能強大,這要歸功於其靈活的 API 設計與幾乎不依賴巨集的實作方式。這種設計讓它能夠輕鬆與其他函式庫整合,而簡潔的 API 使入門變得快速容易。

axum 基於 Tower 函式庫構建,Tower 提供了構建網路服務的抽象層。同時 axum 也使用 hyper 作為底層 HTTP 實作,hyper 為 HTTP/1 與 HTTP/2 提供了高效能的客戶端與伺服器實作。這種分層架構設計讓 axum 既保持了簡潔性,又能充分利用 Rust 生態系統中已驗證的組件。

axum 最吸引人的特點在於它在模式或實踐方面幾乎不會強加太多限制。雖然深入理解細節需要學習 Tower 函式庫的概念,但對於簡單任務這並非必要。基本的網路服務可以快速建立,無需花費大量時間學習框架本身。對於生產環境服務,axum 支援追蹤與指標收集,只需少量配置即可啟用這些功能。

@startuml
!define PLANTUML_FORMAT svg
!theme _none_

skinparam dpi auto
skinparam shadowing false
skinparam linetype ortho
skinparam roundcorner 5
skinparam defaultFontName "Microsoft JhengHei UI"
skinparam defaultFontSize 16
skinparam minClassWidth 100

package "axum 框架架構" {
  component "axum 核心" as Axum {
    [路由系統] as Router
    [處理器] as Handler
    [提取器] as Extractor
  }
  
  component "Tower 中介軟體" as Tower {
    [服務抽象] as Service
    [層級系統] as Layer
    [中介軟體鏈] as Middleware
  }
  
  component "hyper HTTP" as Hyper {
    [HTTP/1 實作] as HTTP1
    [HTTP/2 實作] as HTTP2
    [連線管理] as Connection
  }
}

component "Tokio 執行時" as Tokio

Axum --> Tower : 基於
Tower --> Hyper : 使用
Hyper --> Tokio : 執行於

note right of Axum
  簡潔的 API 設計
  最小化巨集使用
  靈活的組合能力
end note

note bottom of Tower
  可組合的中介軟體
  型別安全的服務
  豐富的生態系統
end note

@enduml

其他主流框架的特性比較

Rust Web 開發生態中還有兩個值得關注的框架:Rocket 與 Actix。Rocket 是一個旨在成為 Rust 版 Ruby on Rails 的 Web 框架,追求開發便利性與生產力。Actix 則是最早的 Rust Web 框架之一,以其高效能著稱,曾在多個基準測試中表現出色。

這兩個框架都面臨相同的歷史包袱:它們大量使用巨集來隱藏實作細節。相比之下,axum 的核心 API 幾乎不使用巨集,這讓程式碼更容易理解與除錯。當遇到問題時,能夠清楚看到實際執行的程式碼,而不是被巨集展開後的複雜結構所困擾。

值得稱許的是,Rocket 與 Actix 都誕生在 Rust 穩定 Future 特質與 async/await 語法之前。在那個時代,使用巨集來簡化非同步程式設計幾乎是必要的選擇。此外這兩個框架在最新版本中都在減少對巨集的依賴方面取得了顯著進展,逐步向更清晰的 API 設計靠攏。

選擇框架時需要考慮專案的具體需求。如果需要快速原型開發與豐富的內建功能,Rocket 是不錯的選擇。如果追求極致效能且熟悉 Actor 模型,Actix 值得考慮。但對於大多數情況,axum 提供了簡潔性與強大功能之間的最佳平衡。

服務架構設計與系統組成

在開始實作之前,需要先規劃整體的服務架構。清晰的架構設計不僅能指導開發過程,也為未來的擴展與維護奠定基礎。對於 Web 服務來說,典型的分層架構已經過時間驗證,能夠滿足大多數應用場景的需求。

典型 Web 服務的三層架構

我們將採用典型的 Web 服務三層架構,它包含負載平衡器、Web 服務本身與狀態服務。負載平衡器負責分散流量到多個服務實例,Web 服務處理業務邏輯,狀態服務則負責資料持久化。這種架構的優勢在於各層職責清晰,便於獨立擴展與維護。

在這個架構中,我們不會實作負載平衡器,假設它已經存在或由基礎設施提供。對於狀態服務我們將使用 SQLite 資料庫,但在實際生產環境中,可能會選擇 PostgreSQL 或 MySQL 等企業級資料庫。SQLite 的優勢在於部署簡單,非常適合開發與測試階段。

@startuml
!define PLANTUML_FORMAT svg
!theme _none_

skinparam dpi auto
skinparam shadowing false
skinparam linetype ortho
skinparam roundcorner 5
skinparam defaultFontName "Microsoft JhengHei UI"
skinparam defaultFontSize 16
skinparam minClassWidth 100

actor "客戶端" as Client

component "負載平衡器" as LB

component "API 服務群組" as APICluster {
  [API 實例 1] as API1
  [API 實例 2] as API2
  [API 實例 N] as APIN
}

database "SQLite\n資料庫" as DB

Client --> LB : HTTP 請求

LB --> API1 : 分散流量
LB --> API2 : 分散流量
LB --> APIN : 分散流量

API1 --> DB : 讀寫資料
API2 --> DB : 讀寫資料
APIN --> DB : 讀寫資料

note right of APICluster
  水平擴展能力
  無狀態設計
  獨立處理請求
end note

note bottom of DB
  集中式狀態管理
  資料持久化
  交易支援
end note

@enduml

API 服務可以透過簡單地增加更多實例來水平擴展。每個 API 服務實例從負載平衡器接收請求,並獨立與資料庫互動以儲存與檢索資料。這種無狀態的服務設計讓擴展變得簡單,只需啟動更多實例即可應對流量增長。

配置管理策略與環境變數

應用程式應該從環境中接收配置,而不是硬編碼在程式碼中。我們將使用環境變數來傳遞配置參數,這種方式非常方便,特別是在部署到容器編排系統如 Kubernetes 時。雖然也可以使用命令列參數或配置檔案,但環境變數在雲端原生環境中已成為標準實踐。

在我們的實作中,只需要幾個配置參數:一個指定資料庫連線字串,一個配置日誌級別,可能還有一個設定服務綁定位址。在大多數情況下,每個 API 服務實例的配置相同,但在某些特殊場景下,可能需要為特定實例指定獨特的參數,例如地理位置資訊或特定的 IP 位址。

在實務中通常綁定到 0.0.0.0 位址,這會綁定到所有網路介面,將路由細節有效地委託給作業系統的網路堆疊。這種做法既簡化了配置,又提供了足夠的靈活性。作業系統的網路堆疊經過多年優化,能夠高效處理連線管理與路由決策。

REST API 介面設計

API 設計是服務開發中最重要的環節之一,好的 API 設計能夠提升開發效率,降低維護成本。我們將建立一個待辦事項應用的 API,這是一個經典的範例,能夠展示 CRUD 操作的完整實作。

待辦事項 API 端點規劃

我們將實作待辦事項的完整生命週期管理,包括建立、讀取、更新、刪除與列表查詢五個基本操作。此外還需要健康檢查端點,用於監控系統狀態。所有 API 路由將放在 /v1 路徑下,這種版本化的設計為未來的 API 演進預留了空間。

建立操作使用 POST 方法,在請求體中提供新待辦事項的資料,成功時回傳建立的物件。列表操作使用 GET 方法,回傳所有待辦事項。讀取操作同樣使用 GET 方法,但在路徑中包含待辦事項的 ID,回傳特定項目的詳細資訊。

更新操作使用 PUT 方法,在路徑中指定 ID,在請求體中提供更新後的資料。刪除操作使用 DELETE 方法,僅需路徑中的 ID 即可。這種 RESTful 設計遵循業界標準,讓 API 的使用直觀易懂。

健康檢查分為兩個端點:活動檢查與就緒檢查。活動檢查用於確認服務程序是否正在執行,就緒檢查則驗證服務是否準備好接收流量,包括資料庫連線是否正常等。這兩個端點對於容器編排系統的健康監控至關重要。

@startuml
!define PLANTUML_FORMAT svg
!theme _none_

skinparam dpi auto
skinparam shadowing false
skinparam linetype ortho
skinparam roundcorner 5
skinparam defaultFontName "Microsoft JhengHei UI"
skinparam defaultFontSize 16
skinparam minClassWidth 100

package "REST API 端點" {
  
  package "/v1/todos" {
    usecase "GET\n列出所有項目" as List
    usecase "POST\n建立新項目" as Create
  }
  
  package "/v1/todos/:id" {
    usecase "GET\n讀取特定項目" as Read
    usecase "PUT\n更新項目" as Update
    usecase "DELETE\n刪除項目" as Delete
  }
  
  package "健康檢查" {
    usecase "GET /alive\n活動檢查" as Alive
    usecase "GET /ready\n就緒檢查" as Ready
  }
}

actor "API 客戶端" as Client

Client --> List
Client --> Create
Client --> Read
Client --> Update
Client --> Delete
Client --> Alive
Client --> Ready

note right of List
  回傳 JSON 陣列
  包含所有待辦事項
end note

note right of Create
  接收 JSON 請求體
  回傳建立的物件
end note

note bottom of Alive
  快速回應檢查
  確認程序運行
end note

@enduml

RESTful 設計原則與實踐

在設計 API 時遵循 RESTful 原則能夠讓介面更加一致與可預測。使用標準的 HTTP 方法表達操作意圖,使用適當的狀態碼表示操作結果,使用 JSON 作為資料交換格式,這些都是被廣泛接受的最佳實踐。

路徑設計應該反映資源的層次結構。在我們的例子中,/v1/todos 代表待辦事項集合,/v1/todos/:id 代表特定的待辦事項。這種層次化的設計清楚表達了資源之間的關係,讓 API 的語義更加明確。

版本化是長期維護 API 的重要策略。透過在路徑中包含版本號,我們可以在不破壞現有客戶端的情況下演進 API。當需要進行重大變更時,可以建立新版本的端點,同時保持舊版本繼續運作,給客戶端充分的遷移時間。

專案依賴配置與工具選擇

建立 Rust Web 服務需要整合多個函式庫,每個都扮演特定的角色。選擇成熟且互相兼容的依賴能夠大幅減少整合問題,讓開發過程更加順暢。我們將依賴現有的 crate 來完成大部分工作,實際上不需要寫太多程式碼,主要是將現有組件組合在一起。

核心依賴函式庫的角色分工

axum 是我們的 Web 框架,提供路由、請求處理與回應生成的基礎設施。它的設計讓我們能夠用最少的樣板程式碼建立 API 端點,同時保持足夠的靈活性來處理複雜場景。axum 與 Tokio 生態系統的深度整合意味著我們能夠充分利用非同步程式設計的優勢。

serde 與 serde_json 處理資料的序列化與反序列化。在 REST API 中,這兩個函式庫至關重要,它們讓我們能夠輕鬆地在 Rust 結構體與 JSON 之間轉換。serde 的 derive 巨集讓這個過程幾乎是自動的,只需在結構體上加上註解即可。

sqlx 是一個非同步 SQL 工具包,我們用它來與 SQLite 資料庫互動。sqlx 的特色在於它在編譯時期驗證 SQL 查詢,這意味著許多潛在的資料庫錯誤能夠在編譯階段被捕捉,而不是等到執行時期才發現。這種靜態檢查大幅提升了程式碼的可靠性。

chrono 函式庫處理日期與時間,它提供了豐富的時間操作功能。啟用 serde 功能讓 chrono 的型別能夠被序列化為 JSON,這對於 API 回應中包含時間戳記至關重要。chrono 的型別設計考慮了時區、夏令時等複雜因素,讓時間處理變得更加可靠。

@startuml
!define PLANTUML_FORMAT svg
!theme _none_

skinparam dpi auto
skinparam shadowing false
skinparam linetype ortho
skinparam roundcorner 5
skinparam defaultFontName "Microsoft JhengHei UI"
skinparam defaultFontSize 16
skinparam minClassWidth 100

package "API 服務依賴關係" {
  
  component "axum" as Axum {
    [路由處理]
    [請求提取]
    [回應生成]
  }
  
  component "sqlx" as SQLx {
    [連線池管理]
    [查詢執行]
    [型別映射]
  }
  
  component "serde" as Serde {
    [序列化]
    [反序列化]
    [衍生巨集]
  }
  
  component "tokio" as Tokio {
    [非同步執行時]
    [任務排程]
    [I/O 驅動]
  }
  
  database "SQLite" as DB
}

Axum --> Tokio : 執行於
SQLx --> Tokio : 執行於
Axum --> Serde : 使用
SQLx --> DB : 連接

note right of Axum
  Web 框架核心
  處理 HTTP 請求
  路由與中介軟體
end note

note right of SQLx
  資料庫存取層
  編譯時期驗證
  非同步查詢
end note

@enduml

追蹤與監控工具整合

tower-http 提供了中介軟體功能,包括追蹤與 CORS 支援。追蹤功能讓我們能夠記錄每個請求的處理過程,對於除錯與效能分析非常有價值。CORS 支援則讓前端應用能夠安全地呼叫我們的 API,這在現代 Web 應用開發中幾乎是必需的。

tracing 與 tracing-subscriber 組成了完整的追蹤系統。tracing 提供記錄追蹤事件的 API,tracing-subscriber 則負責收集與輸出這些事件。這個系統支援結構化日誌,讓日誌不僅僅是文字,而是包含豐富上下文資訊的結構化資料,便於後續分析。

這些依賴的組合經過時間驗證,它們之間的整合相當順暢。特別是 axum 與 sqlx 的配合,讓我們能夠輕鬆地將資料庫操作整合到 HTTP 處理流程中,同時保持程式碼的清晰性。在實際開發中發現這種組合能夠很好地協同工作,很少遇到兼容性問題。

應用程式初始化與啟動流程

應用程式的入口點是整個系統的起點,它負責初始化各個組件並啟動服務。清晰的初始化流程不僅讓程式碼易於理解,也為除錯與維護提供了便利。我們的應用程式遵循一個標準的初始化模式,這個模式在許多生產環境服務中都得到了驗證。

主函式的結構與職責

主函式使用 tokio::main 巨集標註,這個巨集會自動建立 Tokio 執行時並在其中執行我們的非同步程式碼。這種做法讓我們能夠在 main 函式中直接使用 await,而不需要手動建立執行時。雖然失去了一些對執行時的控制,但對於大多數應用來說,預設配置已經足夠。

初始化追蹤功能是第一步。追蹤系統需要在任何其他操作之前設定好,這樣才能記錄完整的啟動過程。接著建立資料庫連線池,這個步驟包括連接資料庫、驗證連線與執行遷移。連線池的建立可能需要一些時間,特別是在執行複雜的遷移腳本時。

建立路由器是核心步驟,它定義了 API 的結構。路由器配置包括端點定義、中介軟體附加與狀態注入。最後啟動 HTTP 伺服器,綁定到指定的位址與埠,開始接收請求。整個流程清晰且容易追蹤,當出現問題時能夠快速定位。

@startuml
!define PLANTUML_FORMAT svg
!theme _none_

skinparam dpi auto
skinparam shadowing false
skinparam linetype ortho
skinparam roundcorner 5
skinparam defaultFontName "Microsoft JhengHei UI"
skinparam defaultFontSize 16
skinparam minClassWidth 100

start

:tokio::main 啟動;

:初始化追蹤系統;
note right
  設定日誌級別
  配置輸出格式
  啟用結構化日誌
end note

:讀取環境變數;

:建立資料庫連線池;
note right
  連接 SQLite
  執行遷移腳本
  驗證連線有效性
end note

:建立 API 路由器;
note right
  定義端點
  附加中介軟體
  注入共享狀態
end note

:綁定網路位址;

:啟動 HTTP 伺服器;

:等待請求處理;

stop

@enduml

追蹤系統的配置與使用

追蹤系統的配置透過環境變數 RUST_LOG 來控制。這個變數支援靈活的過濾語法,可以為不同的模組設定不同的日誌級別。例如可以設定 sqlx 模組只輸出 info 級別的日誌,而 tower_http 模組輸出 debug 級別的詳細資訊。

預設配置應該在資訊量與可讀性之間取得平衡。太少的日誌可能讓問題難以追蹤,太多的日誌則會淹沒重要資訊。在開發環境中可以使用更詳細的日誌級別,而在生產環境中應該更加保守,只記錄真正重要的事件。

tracing-subscriber 提供了靈活的訂閱器系統,可以將日誌輸出到不同的目標。在開發中通常輸出到標準輸出,在生產環境中可能需要輸出到檔案或日誌收集系統。這種靈活性讓相同的追蹤程式碼能夠適應不同的部署環境。

資料庫連線池的建立與管理

資料庫連線池是高效能 API 服務的關鍵組件。連線池維護一組預先建立的資料庫連線,當需要執行查詢時從池中取得連線,使用完畢後歸還。這種模式避免了為每個請求建立新連線的開銷,顯著提升了效能。

SQLite 的連線池配置相對簡單,主要需要指定資料庫檔案路徑。create_if_missing 選項讓資料庫檔案在不存在時自動建立,這在開發與測試中非常方便。在生產環境中可能需要更謹慎,確保資料庫檔案的位置與權限正確設定。

執行遷移是連線池初始化的重要步驟。sqlx 的遷移系統會追蹤已執行的遷移,確保每個遷移只執行一次。遷移腳本應該是冪等的,即使意外執行多次也不會造成問題。這種設計讓資料庫架構的演進變得可控且可預測。

資料模型設計與資料庫架構

資料模型是應用程式的基礎,它定義了資料的結構與關係。好的資料模型設計能夠簡化業務邏輯的實作,也為未來的擴展預留空間。在設計資料模型時需要平衡正規化與效能,找到適合具體應用場景的方案。

SQL 資料表結構設計

待辦事項表的設計包含了幾個核心欄位。id 欄位作為主鍵使用自動遞增的整數,這種設計簡單可靠,適合大多數應用場景。在分散式系統中可能需要考慮使用 UUID,但對於我們的單體應用來說,整數主鍵已經足夠。

body 欄位儲存待辦事項的內容,使用 TEXT 型別可以容納任意長度的文字。completed 欄位是布林值,表示待辦事項是否已完成,預設值為 false。這種設計讓未完成的項目不需要明確設定狀態,簡化了資料建立邏輯。

created_at 與 updated_at 兩個時間戳記欄位記錄了項目的建立與更新時間。這些資訊對於排序、篩選與審計都很有價值。使用 CURRENT_TIMESTAMP 作為預設值讓資料庫自動填充這些欄位,確保時間戳記的準確性與一致性。

所有欄位都設定為 NOT NULL,這種嚴格的約束能夠避免空值帶來的各種問題。在應用層面處理空值邏輯往往比在資料庫層面更複雜,因此在設計階段就排除空值是明智的選擇。這種設計讓資料的語義更加明確,減少了邊界條件的處理。

Rust 結構體與資料庫的映射

Rust 結構體設計需要與 SQL 資料表結構對應。Todo 結構體的欄位直接映射到資料表欄位,型別選擇也反映了資料庫的型別。使用 i64 表示 id 確保能夠容納 SQLite 的整數範圍,String 型別自然對應 TEXT 欄位,bool 映射到 BOOLEAN。

NaiveDateTime 型別來自 chrono 函式庫,它表示沒有時區資訊的日期時間。對於儲存在 SQLite 中的時間戳記,這種型別是合適的選擇。如果需要處理多時區的應用,可能需要考慮使用帶時區的 DateTime 型別,但那會增加複雜度。

衍生 Serialize 特質讓結構體能夠被序列化為 JSON,這對於 API 回應至關重要。衍生 Clone 特質則允許複製結構體實例,在某些處理流程中可能需要。衍生 sqlx::FromRow 是關鍵,它讓 sqlx 能夠自動將資料庫查詢結果轉換為結構體實例。

@startuml
!define PLANTUML_FORMAT svg
!theme _none_

skinparam dpi auto
skinparam shadowing false
skinparam linetype ortho
skinparam roundcorner 5
skinparam defaultFontName "Microsoft JhengHei UI"
skinparam defaultFontSize 16
skinparam minClassWidth 100

class "Todo 結構體" as Todo {
  - id: i64
  - body: String
  - completed: bool
  - created_at: NaiveDateTime
  - updated_at: NaiveDateTime
  --
  + list(pool) -> Vec<Todo>
  + read(pool, id) -> Todo
  + create(pool, data) -> Todo
  + update(pool, id, data) -> Todo
  + delete(pool, id) -> ()
}

entity "todos 資料表" as Table {
  * id: INTEGER (PK)
  * body: TEXT
  * completed: BOOLEAN
  * created_at: TIMESTAMP
  * updated_at: TIMESTAMP
}

Todo ..|> Table : 映射

note right of Todo
  衍生特質:
  - Serialize (JSON 轉換)
  - Clone (複製實例)
  - FromRow (資料庫映射)
end note

note bottom of Table
  約束:
  - 所有欄位 NOT NULL
  - id 自動遞增
  - 預設時間戳記
end note

@enduml

CRUD 操作的完整實作

實作 CRUD 操作是 API 開發的核心工作。每個操作都需要正確處理資料庫互動、錯誤處理與結果回傳。透過將這些操作封裝為結構體的方法,我們能夠建立清晰且可重用的資料存取層。

查詢操作的實作策略

列表查詢操作相對簡單,它執行一個 SELECT 查詢並回傳所有記錄。使用 query_as 巨集讓 sqlx 知道查詢結果應該映射到哪個型別。fetch_all 方法執行查詢並收集所有結果到向量中。這種一次性讀取所有資料的方式適合資料量不大的場景。

單項查詢操作增加了 WHERE 子句來過濾特定記錄。使用 bind 方法將參數綁定到查詢中,這種參數化查詢能夠防止 SQL 注入攻擊。fetch_one 方法期望查詢恰好回傳一條記錄,如果記錄不存在或有多條記錄都會回傳錯誤。

錯誤處理使用 map_err 將 sqlx 的錯誤型別轉換為應用程式的錯誤型別。這種轉換讓上層程式碼不需要直接處理資料庫特定的錯誤,提供了更好的抽象層次。Into 特質的使用讓轉換過程簡潔,只要定義了適當的 From 實作即可。

在實際應用中可能需要為列表查詢增加分頁、排序與過濾功能。這些增強功能可以透過增加額外的參數與修改 SQL 查詢來實現。保持方法簽名的簡潔性很重要,可以考慮使用建造者模式來處理複雜的查詢參數。

寫入操作的設計考量

建立操作使用 INSERT 語句並配合 RETURNING 子句。RETURNING 子句讓資料庫在插入記錄後立即回傳新建立的記錄,包括自動生成的 id 與預設的時間戳記。這種做法避免了需要額外查詢來取得新記錄的情況,提升了效率。

更新操作使用 UPDATE 語句修改現有記錄。除了更新使用者提供的欄位,還使用 datetime(’now’) SQL 函式更新 updated_at 欄位。讓資料庫處理時間戳記確保了時間的準確性,避免了客戶端與伺服器時間不同步的問題。同樣使用 RETURNING 子句回傳更新後的記錄。

刪除操作相對簡單,它執行 DELETE 語句並使用 execute 方法。與查詢操作不同,刪除不需要回傳資料,只需確認操作成功。回傳空元組表示操作完成但無資料回傳,這種語義在 Rust 中很常見。

所有寫入操作都使用參數綁定來防止 SQL 注入。即使在內部 API 中,保持這種安全實踐也很重要。未來如果需要開放 API 或整合外部系統,這種防禦性程式設計能夠避免安全漏洞。

這些 CRUD 操作形成了資料存取層的基礎。它們提供了清晰的介面,讓上層的路由處理器能夠專注於 HTTP 請求處理,而不需要關心資料庫操作的細節。這種分層設計是構建可維護系統的關鍵原則。

建構生產級 REST API 的關鍵要素

將基礎的 CRUD 操作組裝成完整的 REST API 服務還需要考慮許多細節。錯誤處理、請求驗證、回應格式化、中介軟體配置,這些看似瑣碎的工作實際上決定了 API 的品質與可靠性。在實務開發中,這些細節往往比核心業務邏輯花費更多時間。

理解 axum 的提取器系統是關鍵。提取器讓我們能夠以型別安全的方式從請求中提取資料,無論是路徑參數、查詢字串、請求體還是標頭。這種聲明式的方法讓程式碼更加清晰,編譯器能夠在編譯時期捕捉許多潛在錯誤。

中介軟體的配置讓我們能夠橫切關注點,例如日誌記錄、錯誤處理、認證授權等。Tower 的中介軟體系統非常強大,可以用型別安全的方式組合多個中介軟體。這種組合能力讓我們能夠建構複雜的請求處理管道,同時保持程式碼的模組化。

測試是確保 API 品質的重要環節。axum 的設計讓單元測試變得相對容易,可以直接測試路由處理器而不需要啟動完整的伺服器。整合測試則可以使用 axum 提供的測試工具來模擬完整的 HTTP 請求回應週期。

透過這篇文章展示的完整實作流程,從框架選擇到資料庫設計,從依賴配置到 CRUD 實作,我們建立了一個可靠的 REST API 服務基礎。這個基礎可以作為實際專案的起點,根據具體需求進行擴展與客製化。Rust 強大的型別系統與 axum 靈活的設計讓這種擴展變得安全且可控,為台灣開發者提供了建構高品質 Web 服務的完整技術方案。