用 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,建議你安裝以下擴展:

安裝依賴項

在開始編碼之前,我們需要安裝依賴項。在這個階段,我們只需要其中的三個:tide, async-stdserde

正如我前面解釋的,tide 是我們用來構建 API 的 Web 框架。

async-std 是異步運行時。默認情況下 Rust 不提供異步運行時,所以我們需要安裝一個。目前有兩種流行的選擇:tokioasync-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