【開発レポート】Rustで挑む「理想のWebフレームワーク」構築 2.5 – ToDoアプリ実装で見えた「生産性」と「UX」

【開発レポート】Rustで挑む「理想のWebフレームワーク」構築 2.5 – ToDoアプリ実装で見えた「生産性」と「UX」

お疲れ様です、tomaです。

前回の記事では、管理画面(Admin UI)の大規模なリファクタリングを行い、「ボイラープレートの殲滅」に向けた戦果を報告しました。
今回は、次の大きな機能開発(認証システムのプラグイン化など)に進む前に、「実際にこのフレームワークを使ってアプリを作るとどうなるのか?」 という、いわば「実戦テスト」を行いましたので、その記録を 「レポート2.5」 として残しておきます。

作成したのは、Webアプリの登竜門である 「ToDoアプリ」 です。
たかがToDo、されどToDo。
ここには、DjangoユーザーがRustに求めていた「書き心地」と、Rustならではの「安全性」の融合が詰まっていました。

1. 今回のクエスト:ただ動くToDoではなく「使える」ToDoを

今回のサンプルプロジェクト(src/controllers/todo.rs)の実装にあたって、単に「動けばいい」というレベルは卒業することにしました[1]。
目指したのは、以下の要件を満たす モダンなWebアプリケーションのショーケース です。

  • コードが汚れない:コントローラーに「お決まりの記述」を書かない。
  • UXが死なない:バリデーションエラーで入力内容を消さない。
  • セキュリティが堅い:他人のタスクは絶対に見せない。

これらをRustの型システムの上で、いかに「Djangoライク」に実現したかをご紹介します。

2. 魔法の「AppTemplate」でコンテキストを自動注入

Djangoを書いているとき、テンプレートで {{ user.username }} と書くだけでユーザー名が表示されるのは当たり前ですよね。
しかし、Rust(Rocket)でこれを素直にやろうとすると、すべてのコントローラーで user オブジェクトを取得し、毎回テンプレートに渡すという「苦行」が発生します。渡し忘れれば500エラー、書くのも面倒です[1]。

そこで、AppTemplate という仕組みを導入しました。

  • 仕組みsrc/fairings/context.rs がリクエストの入り口でユーザー認証やCSRFトークン生成を済ませ、キャッシュしておきます[1]。
  • 効果:レスポンスを返す際、AppTemplate が自動的にそれらをテンプレート変数にマージします[1]。

これにより、コントローラーのコードは「ToDoのビジネスロジック」だけに集中できるようになり、Djangoのような「魔法」を型安全に再現できました。

3. 「保存」か「再描画」か? UXを支える型定義

Webフォームの開発で最もUXを損なうのが、「入力ミスでエラーになった瞬間、入力内容が全て消える」 現象です。
前回の管理画面のリファクタリングでも触れましたが、今回のToDoアプリではこの挙動を徹底して排除しました[2]。

ここで活躍するのがRustの Result 型です。

// 成功ならリダイレクト、失敗ならテンプレート再描画
Result<Flash<Redirect>, AppTemplate>
  • 成功時 (Ok)Flash::success と共に一覧画面へリダイレクトします[3]。
  • 失敗時 (Err)AppTemplate を返し、フォームを再レンダリングします[3]。

重要なのは、エラー時に「送信されたフォームデータ」も一緒にテンプレートに渡している点です。テンプレート側(form.html.tera)で value="{{ form.title }}" のように値を復元することで、ユーザーはストレスなく修正を行えます[3][4]。
「リダイレクト」と「レンダリング」を型レベルで明示的に使い分ける。これがRustらしいWeb開発の気持ちよさです。

4. SeaORMによる「N+1問題」回避と鉄壁のガード

データアクセス層には SeaORM を採用していますが、ここでも実践的なパターンを組み込みました。

  • N+1問題の回避:ToDoリストと一緒に「カテゴリ(Group)」を表示したい場合、find_also_related(Group) を使うことで、一度のクエリで関連データも効率よく取得しています[3]。
  • マルチテナント風セキュリティ
    filter(todo::Column::UserId.eq(user.user.id))

    このように、クエリ構築時に必ず「ログインユーザーのID」でフィルタリングを行うことで、他人のデータが見えてしまう事故を根本から防いでいます[3]。

5. まとめ:冒険の装備は整いつつある

今回のToDoアプリ実装を通じて、「Rustでも生産性は高くできる」 という手応えを強く感じました[4]。
マクロやFairing(ミドルウェア)を組み合わせることで、DjangoやRailsのような「レール」を敷きつつ、その下にはRustの堅牢な大地がある。そんな理想の形が見えてきました。

ソースコードの src/controllers/todo.rs には、各関数の役割やセキュリティ上の考慮点を詳細なコメントとして残しています[4]。
もし興味があれば、リポジトリを覗いてみてください。

さて、装備(サンプル実装)の点検は完了です。
次こそは、新しい機能の開拓(認証プラグインやCLIツールなど)へ進みたいと思います[5]。

それでは、また次のセーブレポートで。
toma

Comments

No comments yet. Why don’t you start the discussion?

    コメントを残す

    メールアドレスが公開されることはありません。 が付いている欄は必須項目です