RustのWebアプリケーション開発でよく利用するクレート(2023年版)
RustのWebアプリケーション開発でよく利用するクレートをまとめてみました。 選定方法は、awesome-rustや各リポジトリのスター数などから独断と偏見で記載しています。あくまで個人的な見解なので、「こんなのもあるよ」「ここは違うんじゃないの」などあればお気軽にコメントくださいませ。
Webフレームワーク
Webアプリケーション開発においてWebフレームワークの利用は必須といえるでしょう。現時点ではRustでデファクタとなっているWebフレームワークはないのでactix-web
、rocket
、axum
あたりから選ぶことが多いでしょう。
高機能なactix-web
はまだまだ人気ですが、最近はrocket
の利用が増えている印象です。
Rocket (Star 21.1k)
- RocketはRust用の非同期ウェブフレームワークで、ユーザビリティ、セキュリティ、拡張性、スピードに重点を置いている
#[get("/")]
fn index() -> &'static str {
"Hello, world!"
}
actix-web (Star 18.1k)
- Actix Webは、パワフルで実用的、そして非常に高速なRust用Webフレームワーク
#[get("/hello/{name}")]
async fn greet(name: web::Path<String>) -> impl Responder {
format!("Hello {name}!")
}
axum (Star 11.2k)
- axumは、人間工学とモジュール性に重点を置いたウェブアプリケーションフレームワーク
async fn root() -> &'static str {
"Hello, World!"
}
リレーショナルデータベース
リレーショナルデータベースを扱う場合、主に「ORMのライブラリを使うケース」と「クエリビルダー/オブジェクマッパーのライブラリを使うケース」の2つがあります。
ORMを使う場合は、ほぼdiesel
が使われており、たまにsea-orm
が使われてるという印象です。また、ORMを使いたくない場合は、sqlx
が使われます。
diesel (Star 10.7k)
- Rustのための安全で拡張可能なORMとクエリビルダ
- PostgreSQL、MySQL、SQLiteをサポートしている
// Entity
#[derive(Queryable, Selectable)]
#[diesel(table_name = crate::schema::posts)]
#[diesel(check_for_backend(diesel::pg::Pg))]
pub struct Post {
pub id: i32,
pub title: String,
pub body: String,
pub published: bool,
}
// find all models
let results = posts
.filter(published.eq(true))
.limit(5)
.select(Post::as_select())
.load(connection)
.expect("Error loading posts");
sea-orm (Star 4.6k)
- SeaORMは、動的言語に慣れ親しみながらRustでWebサービスを構築するのに役立つリレーショナルORM
// Entity
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
#[sea_orm(table_name = "cake")]
pub struct Model {
#[sea_orm(primary_key)]
pub id: i32,
pub name: String,
}
// find all models
let cakes: Vec<cake::Model> = Cake::find().all(db).await?;
sqlx (Star 9.3k)
- SQLを直接書くことでコンパイル時にSQLを検証することができるようにしている
- また、PostgreSQL、MySQL、SQLite、MS SQLをサポートしている
// コンパイル時にSQLの内容を検証できる
let countries = sqlx::query!(
"
SELECT country, COUNT(*) as count
FROM users
GROUP BY country
WHERE organization_id = ?
",
organization_id
)
.fetch_all(&pool) // -> Vec<{ country: String, count: i64 }>
.await?;
// countries[0].country
// countries[0].count
HTMLテンプレートエンジン
WebアプリケーションでHTMLを返す場合はテンプレートエンジンが必要になってきます。askama
が使われることが多い気がする。
- askama (Star 2.3k)
- AskamaはJinjaベースのテンプレートレンダリングエンジンを実装している
- 型安全でコンパイル時にテンプレートからRustコードを生成する
- tera (Star 2.8k)
- Tera は Jinja2 と Django テンプレート言語にインスパイアされたテンプレートエンジン
- Jinja2/Djangoと100%互換を目指していない
- maud (Star 1.6k)
- MaudはRust用のHTMLテンプレートエンジンで、
html!
というマクロが実装されており、マークアップを特殊なRustコードにコンパイルする - このユニークなアプローチにより、Maudのテンプレートは非常に高速で、型安全性が高く、デプロイしやすくなっている
- MaudはRust用のHTMLテンプレートエンジンで、
シリアライズ・デシリアライズ
Rustではシリアライズ・デシリアライズ時にはserde
が利用されます。また、Web APIでJSONを扱う場合はserde-json
も一緒に利用されます。
serde-rs/serde (Star 7.3k)
- Rustのデータ構造に対してデータをシリアライズ・デシリアライズできる
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug)]
struct Point {
x: i32,
y: i32,
}
fn main() {
let point = Point { x: 1, y: 2 };
// pointをJSON文字列に変換(シリアライズ)
let serialized = serde_json::to_string(&point).unwrap();
println!("serialized = {}", serialized);
//=> serialized = {"x":1,"y":2}
// JSON文字列をpointに変換(デシリアライズ)
let deserialized: Point = serde_json::from_str(&serialized).unwrap();
println!("deserialized = {:?}", deserialized);
//=> deserialized = Point { x: 1, y: 2 }
}
時刻
標準ライブラリのstd::time
では時刻を扱うための基本的な型のみが定義されているので、暦やタイムゾーンなどを扱う場合はchrono
が利用されます。
chrono (Star 2.8k)
- chronoは、日付と時刻を正しく操作するために必要なすべての機能を提供することを目指している
- また、
serde
にも対応しており、シリアライズ・デシリアライズも可能
let utc: DateTime<Utc> = Utc::now(); // e.g. `2014-11-28T12:45:59.324310806Z`
let local: DateTime<Local> = Local::now(); // e.g. `2014-11-28T21:45:59.324310806+09:00`
認証
JWTやOauth2を利用して認証をする場合、それぞれライブラリがあるので利用を検討できます。
- jsonwebtoken: RustのJWT(JSON Web Token)のライブラリ
- oauth2-rs: 拡張可能で強く型付けされたRustのOAuth2(RFC6749)のライブラリ
エラーハンドリング
- anyhow (Star 4.2k) :
std::error::Error
をもとに構築された柔軟な具象エラー型。エラーの型がたくさんハンドリングする必要がある場合に、エラーハンドリングを楽にしてくれる