ポケモンを衝動買いしたものの、全然やる暇がないですね。。。
時間は作るものらしいので、ポケモンやる時間作ります(現在進行系でブログ記事に時間を使ってますが)。
今日は、ちまちま作っているOSSの fakey-cognito で使っている RustのWebフレームワークである warp を紹介します。
RustのWebフレームワーク
Rustはなんとなくシステムプログラミングのイメージが強い感じがありますが、実際書いてみるとそうでもない印象が強い言語ではあります。
もともとRustが解決しようとしていた分野は、システムプログラミング分野だったとは思います。実際にRustのスローガン自体も、過去はシステムプログラミング言語を標榜していたはずです。ただ、書き始めてみると、安全性と生産性、そして時には詳細な制御でパフォーマンスを引き出すこともできる類まれな言語だということが言えると思います。
このような背景から、近年のRustではWebフレームワークも複数存在しています。
Webフレームワークの種類は以下のCyber Agentのブログ記事にまとまっているので、どのようなフレームワークがあるのかはそちらを参考にしていただくとして、今回は、その中でも warp を紹介したいと思います。
warp
warp は非同期に関しては tokio をベースとして、HTTPは低レイヤーのHTTPを触ることが可能な hyper というクレートをベースにしています。
実のところ、fakey-cognitoは最初 hyper ではじめようと思っていました(ちょうど作ろうとしているところ、Software Designで紹介されていたので触発されました)。ただそこまで低レイヤーを触る必要がなかったため、hyperをベースとした warp で作ることにしました。
ちなみにいわゆるSpring frameworkのようなルーティング記述のわかりやすさを求めるのであれば、Actix Webのほうがおすすめできると思います。パフォーマンス的にも高評価なフレームワークです。ただ、以下も加味してwarpを選択しました。
① hyperをベースとしている
② 型付けが強い
③ どうせ個人開発だし面白そうなのを触ろう
はい、面白さを優先しました。作るものとしてもJSON APIであり、高度なレンダリングサポートも不要で、やるなら今しかない!という感じで選択しました。
実際にサンプルコードを紹介します。
use std::convert::Infallible; use warp::Filter; async fn hello(name: String) -> Result<impl warp::Reply, Infallible> { Ok(format!("hello {}!", name)) } #[tokio::main] async fn main() { let addr = [0, 0, 0, 0]; let port = 18081; warp::serve( warp::path!("example" / String) .and(warp::get()) .and_then(hello) ) .run((addr, port)) .await; }
シンプルですが /example/bob
にGETリクエストすると、 "hello bob!" という文字列を返すだけのサーバーです。
warpは Filter という構成要素を使って様々な処理をするようになっています。 warp::serve
に渡している部分がそうです。
最後に Handler
でレスポンスを作成して返します。
Filterではパスルーティングや受け付けるメソッド、パラメータ抽出、ヘッダー指定・抽出、フォームデータ、ログなど様々なことができるようになっており、それらを組み合わせていくことでサーバーの処理を作ることができます。
また、独自の型によりバリデーションもできるので、型をメインでシステム構築したい人にはハマるフレームワークになっているかと思います。
参考
caddi.tech
まとめ: ハマれそうなら使ってみても良いかも
warpはHTTPの機能としては十分ですがテンプレートなどは自前であったりと、APIサーバーとしてはよいですがフルスタックなフレームワークに慣れていると色々と大変な部分もあるかと思います。ただ、型付けでしっかりやれる点は、Rustっぽさがあり、Rustでやっているならこのくらいでもよいのでは!と感じる部分も多くあります。
warpに限らず、フレームワークも色々あったりするので、WebサーバーをRustで書いてみませんか?というご紹介でした。