Overview
このチュートリアルでは、Rocket ウェブフレームワークを使用してRustウェブアプリケーションを作成する方法を学びます。Rustドライバーを使用すると、メモリ管理、有効期間、データベースプーリングなどの機能を活用して、アプリケーションのパフォーマンスを向上させることができます。
このチュートリアルを完了すると、 CRUD操作を実行するためのルートを含むウェブアプリケーションが作成されます。
前提条件
開発環境にRust 1.74 以降とRustパッケージマネージャーの Rust がインストールされていることを確認してください。
Rustおよび Cardgo をインストールする方法の詳細については、 Rust のダウンロードとインストールに関するRust の公式ガイドを参照してください。
また、 MongoDB Atlasクラスターを設定する必要があります。クラスターの作成方法については、 クイック スタートガイドの MongoDB配置の作成 ステップを参照してください。接続文字列を安全な場所に保存して、チュートリアルの後半で使用します。
手順
非同期ランタイムを選択します。
Rustドライバーを使用する場合は、同期ランタイムまたは非同期ランタイムのいずれかを選択する必要があります。このチュートリアルでは、API を構築するのに適した非同期ランタイムを使用します。
ドライバーはデフォルトで非同期tokio ランタイムで動作します。
利用可能なランタイムの詳細については、非同期 API と同期 API に関するガイド を参照してください。
サンプルデータを挿入します。
INSERT DOCUMENT ボタンを選択し、サンプルアプリリポジトリに別の string_data.json ファイルの内容を貼り付けます。
データを挿入すると、 recipesコレクションにサンプルドキュメントが表示されます。
Rocket をインストールします。
IDE を開き、プロジェクトディレクトリを入力します。プロジェクトルートから次のコマンドを実行して、Rocket Webフレームワークをインストールします。
cargo add -F json rocket
Cargo.tomlファイルの依存関係リストに rocket のエントリが含まれていることを確認します。
また、Rocket によって開発されたcrateを追加する必要があります。これにより、 MongoDBクライアントによって行われる非同期接続のコレクションプールをラッパーを使用して管理できます。このcrateを使用すると、 MongoDB のデータベースとコレクションをパラメーター化し、各アプリ関数が独自の接続を受け取って使用することができます。
次のコマンドを実行して、rocket_db_pools crateを追加します。
cargo add -F mongodb rocket_db_pools
Cargo.tomlファイルの依存関係リストに、mongodb の機能フラグを含む rocket_db_pools のエントリが含まれていることを確認します。
ロックを構成します。
breadデータベースを使用するように Ruby を構成するには、プロジェクトルートに Rocket.toml というファイルを作成します。構成設定を読み取るためにこのファイルを検索します。このファイルにMongoDB接続文字列を保存することもできます 。
次の構成を Rocket.toml に貼り付けます。
[default.databases.db] url = "<connection string>"
Rocket の構成の詳細については、Rocket ドキュメントの「 構成 」を参照してください。
アプリの構造について学びます。
API の記述を開始する前に、単純な Rocketアプリの構造について学習し、アプリケーション内に対応するファイルを作成します。
次の図は、Rockeアプリに必要なファイル構造を示し、各ファイルの機能を説明しています。
. ├── Cargo.lock # Dependency info ├── Cargo.toml # Project and dependency info ├── Rocket.toml # Rocket configuration └── src # Directory for all app code ├── db.rs # Establishes database connection ├── main.rs # Starts the web app ├── models.rs # Organizes data └── routes.rs # Stores API routes
前の図に従って、srcディレクトリとそれに含まれるファイルを作成します。この点で、ファイルは空にできます。
データベース接続を設定します。
以下のコードをdb.rs ファイルに貼り付けてください。
use rocket_db_pools::{mongodb::Client, Database}; pub struct MainDatabase(Client);
また、データベース構造体 を Rocketインスタンスにアタッチする必要があります。main.rs では、次のコードに示すように、データベースを初期化し、アタッチします。
mod db; mod models; mod routes; use rocket::{launch, routes}; use rocket_db_pools::Database; fn rocket() -> _ { rocket::build() .attach(db::MainDatabase::init()) .mount() }
IDE では、mount() に引数が欠落しているというエラーが発生する場合があります。後の手順でルートを追加するため、このエラーは無視できます。
データモデルを作成します。
データを表すための一貫した有用な構造体を定義することは、型の安全性を維持し、ランタイムエラーを減らすために重要です。
models.rsファイルには、ケーキのレシピを表す Recipe 構造体を定義します。
use mongodb::bson::oid::ObjectId; use rocket::serde::{Deserialize, Serialize}; pub struct Recipe { pub id: Option<ObjectId>, pub title: String, pub ingredients: Vec<String>, pub temperature: u32, pub bake_time: u32, }
APIルートを設定します。
ルーティングにより、プログラムはリクエストを適切なエンドポイントに送信し、データを送受信できます。ファイルroutes.rs にはAPIで定義されたすべてのルートが保存されています。
次のコードを routes.rsファイルに追加して、インデックスルートと単純な get_recipes() ルートを定義します。
use crate::db::MainDatabase; use crate::models::Recipe; use mongodb::bson::doc; use rocket::{futures::TryStreamExt, get, serde::json::Json}; use rocket_db_pools::{mongodb::Cursor, Connection}; pub fn index() -> Json<Value> { Json(json!({"status": "It is time to make some bread!"})) } pub async fn get_recipes(db: Connection<MainDatabase>) -> Json<Vec<Recipe>> { let recipes: Cursor<Recipe> = db .database("bread") .collection("recipes") .find(None, None) .await .expect("Failed to retrieve recipes"); Json(recipes.try_collect().await.unwrap()) }
残りのルートを作成する前に、Rocke のメイン起動関数にルートを追加します。
main.rs で、ファイルが次のコードのようになるように引数を mount() に置き換えます。
mod db; mod models; mod routes; use rocket::{launch, routes}; use rocket_db_pools::Database; fn rocket() -> _ { rocket::build().attach(db::MainDatabase::init()).mount( "/", routes![ routes::index, routes::get_recipes, routes::create_recipe, routes::update_recipe, routes::delete_recipe, routes::get_recipe ], ) }
エラー処理と応答を実装します。
アプリでは、 CRUD操作の予期しない結果に対応するために、エラー処理とカスタム応答を実装する必要があります。
次のコマンドを実行中して serde_json crateをインストールします。
cargo add serde_json
このcrateには、 JSON値を表す Value列挙が含まれています。
Rocket の status::Custom 構造体を使用して、ルートがHTTPステータス コードを返すように指定できます。これにより、 HTTPステータス コードと返すカスタム データを指定できます。次の手順では、status::Custom 型を返すルートを記述する方法について説明します。
CRUD操作ルートの書込み (write)。
作成
MongoDBでデータを作成しようとすると、次の 2 つの結果が考えられます。
ドキュメントは正常に作成されたため、アプリは
HTTP 201を返します。挿入中にエラーが発生したため、アプリは
HTTP 400を返します。
次のルートを routes.rsファイルに追加して、create_recipe() ルートを定義し、エラー処理を実装します。
pub async fn create_recipe( db: Connection<MainDatabase>, data: Json<Recipe>, ) -> status::Custom<Json<Value>> { if let Ok(res) = db .database("bread") .collection::<Recipe>("recipes") .insert_one(data.into_inner(), None) .await { if let Some(id) = res.inserted_id.as_object_id() { return status::Custom( Status::Created, Json(json!({"status": "success", "message": format!("Recipe ({}) created successfully", id.to_string())})), ); } } status::Custom( Status::BadRequest, Json(json!({"status": "error", "message":"Recipe could not be created"})), ) }
読み取り
MongoDBからデータを読み込もうとすると、次の 2 つの結果が考えられます。
一致するドキュメントのベクトルを返します。
一致するドキュメントがないかエラーが発生したため、空のベクトルを返します。
これらの結果が予想されるため、get_recipes() ルートを次のコードで置き換えます。
pub async fn get_recipes(db: Connection<MainDatabase>) -> Json<Vec<Recipe>> { let recipes = db .database("bread") .collection("recipes") .find(None, None) .await; if let Ok(r) = recipes { if let Ok(collected) = r.try_collect::<Vec<Recipe>>().await { return Json(collected); } } return Json(vec![]); }
その他の操作
get_recipe()update_recipe()delete_recipe()サンプルアプリリポジトリの route.rsファイルから 、 、 ルートをコピーできます。
CRUD操作を実行するためのテストルート。
ターミナルで次のコマンドを実行中してアプリケーションを起動します。
cargo run
別のターミナルウィンドウで、次のコマンドを実行して、create_recipe() ルートをテストします。
curl -v --header "Content-Type: application/json" --request POST --data '{"title":"simple bread recipe","ingredients":["water, flour"], "temperature": 250, "bake_time": 120}' http://127.0.0.1:8000/recipes
{"status":"success","message":"Recipe (684c4245f5a3ca09efa92593) created successfully"}
次のコマンドを実行して、get_recipes() ルートをテストします。
curl -v --header "Content-Type: application/json" --header "Accept: application/json" http://127.0.0.1:8000/recipes/
[{"_id":...,"title":"artisan","ingredients":["salt","flour","water","yeast"],"temperature":404,"bake_time":5}, {"_id":...,"title":"rye","ingredients":["salt"],"temperature":481,"bake_time":28},...]
次のコマンドを実行して、delete_recipe() ルートをテストします。<id> プレースホルダーを、コレクション内の既知の _id 値に置き換えます。これは 68484d020f561e78c03c7800 のようになります。
curl -v --header "Content-Type: application/json" --header "Accept: application/json" --request DELETE http://127.0.0.1:8000/recipes/<id>
{"status":"","message":"Recipe (68484d020f561e78c03c7800) successfully deleted"}
まとめ
このチュートリアルでは、Rocke を使用してCRUD操作を実行するための簡単なウェブアプリケーションを構築する方法を学習しました。
リソース
CRUD操作の詳細については、次のガイドを参照してください。