用 Rust 構建 API 系列教程:第一部分
大家好,我是胖蟹哥。
今天給大家帶來一個系列:使用 Rust 構建 API。
在這個系列教程中,我將向你展示如何在 Rust 中構建一個簡單的 API。由於我自己也是 Rust 的初學者,還有很多東西我需要學習。所以其中有不對的地方,歡迎批評指正。
這個系列一共分三部分。
第一部分將介紹基礎知識,我將解釋如何設置項目,並創建一個端點,返回一個 Hello World!信息。
在第二部分中,我將把 API 連接到 MongoDB,並添加兩個端點來從數據庫中創建和檢索文檔。
在第三部分也是最後一部分,我將向你展示如何構建身份驗證中間件來保護其中一個端點。
Web 框架
我決定使用 tide[1] 作爲 Web 框架。雖然比不上 actix[2] 流行(目前最流行的),但是我對 tide 更有感覺,在我看來它更簡單。
項目設置
讓我們開始設置這個項目。
首先,確保你已經安裝了 Rust 和 Cargo[3]。
鍵入以下命令,使用 cargo 創建一個新項目:
cargo new rust-api-example-part-1
開始準備些代碼,選擇一個你最喜歡的編輯器開始。
如果你使用 VS Code,建議你安裝以下擴展:
-
rust-analyzer,之前有介紹過,這個比官方的更好用;
-
TOML Language Support,支持 TOML 文件格式語法高亮,支持 TOML 格式化,還計劃支持 JSON 等格式和 TOML 轉換;裝這個插件,是因爲 Cargo 的配置文件是這種格式。這也是我比較喜歡的格式,比太喜歡 YAML。
安裝依賴項
在開始編碼之前,我們需要安裝依賴項。在這個階段,我們只需要其中的三個:tide
, async-std
和 serde
。
正如我前面解釋的,tide
是我們用來構建 API 的 Web 框架。
async-std
是異步運行時。默認情況下 Rust 不提供異步運行時,所以我們需要安裝一個。目前有兩種流行的選擇:tokio
和 async-std
。
這有點煩人,因爲這意味着你需要確保將在項目中使用的所有異步庫都必須與你選擇的異步運行時兼容。
tide
要求我們使用 async-std
,所以我們將安裝這個運行時。
serde
是一個序列化和反序列化數據的框架(例如將 JSON 對象轉換爲 Rust 結構)。
打開 Cargo.toml 文件,並在 [dependencies] 下添加以下內容:
tide = "0.16"
async-std = { version = "1", features = ["attributes"] }
serde = { version = "1.0", features = ["derive"] }
你可以像我爲 async-std
所做的那樣指定額外的特性,這裏,我們將需要 attributes
特性。
確保它能運行
默認情況下,在使用 cargo 創建項目時,應該有一個包含示例函數的默認 src/main.rs 文件。確保它能運行:
cargo run
第一次運行會比較慢。
在最後應該會打印:Hello,world!
接下來就是正式寫代碼的時候了。
開始編碼
在 src/main.rs 文件中,添加如下代碼:
#[async_std::main]
async fn main() -> tide::Result<()> {
let app = tide::new();
app.listen("127.0.0.1:8080").await?;
return Ok(());
}
main
現在是異步的,因爲我們在前面添加了 async
關鍵字。爲了能正確工作,我們需要添加一個運行時,這正是 #[async_std::main]
所做的。它是一個 "attribute" 宏,只是將我們的 main
函數包裝在一個異步運行時中。
這個函數返回 tide::Result<()>
,這意味着它要麼什麼也不返回 (Ok(())
) ,要麼返回一個 Tide 錯誤。
在函數內部,我們創建一個新的 Tide 實例,然後調用函數 listen
啓動端口 8080
上的本地服務器。
如果你現在嘗試訪問 API,你會得到一個 404
,因爲我們還沒有定義任何路由。
讓我們創建第一個控制器(controller),在 src/main.rs
中的 main
函數上面添加以下內容:
use tide::Request;
#[derive(Clone, Debug)]
struct State {}
async fn hello(_req: Request<State>) -> tide::Result {
return Ok("Hello world!".into());
}
hello
控制器是異步的,只有一個參數。因爲我們實際上並沒有使用這個參數,所以我們可以在每個約定中添加一個前導下劃線。_req
參數的類型是 Request
(從 tide
導入) ,它需要一個 State
,這就是爲什麼我定義了一個空的 State
結構體。
State
結構體需要實現 Clone
特性(trait),因此我們使用從 serde
派生(derive
)的宏(marco)來實現它。
控制器返回類型得是 tide::Result
。
至於實現,我們只是返回 &str
類型值,並使用 .into()
函數將其轉換爲 tide::Result
。
這就是我們的控制器。現在我們需要對 main
函數做一些修改。改爲下面的代碼:
#[async_std::main]
async fn main() -> tide::Result<()> {
let mut app = tide::with_state(State {});
app.at("/hello").get(hello);
app.listen("127.0.0.1:8080").await?;
return Ok(());
}
我已經修改了我們應用程序的初始化,使其通過一個空 State
。稍後當我們需要傳遞數據庫連接時,這將非常有用。
然後我添加了端點 GET /hello
。
現在,如果你運行這個應用程序,然後在瀏覽器訪問 http://localhost:8080/hello
,你應該能看到 Hello world!
。
結尾
這就是該系列的第一部分,希望它對你有所幫助。
關於 Tide,可以訪問倉庫首頁瞭解更多詳細內容。
參考資料
[1]
tide: https://github.com/http-rs/tide
[2]
actix: https://github.com/actix/actix
[3]
Rust 和 Cargo: https://www.rust-lang.org/tools/install
掃碼關注「Rust 編程指北」
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/fzisds3BDnb6u_UR0L1V1Q