RustのRocketとSqlxでクリーンアーキテクチャっぽいやつを作ってみました

2023/09/25

Rust の Rocket と sqlx でクリーンアーキテクチャっぽくして、ディレクトリとか モジュールもなるべくいい感じに分けつつ、テストもしやすい・モックも作りやすい状態を、頑張って作ってみました。

目次

以前 Axum でも同じようなことをやりました

以前 Axum でも同じようなことをやってみていました。ワイの歴代最多スター数を誇るリポジトリが下記です。

https://github.com/edo1z/rust-axum-sqlx-sample

このリポジトリの Axum のバージョンはもう結構古いですので、今やろうとしたら全体的に修正が必要だとは思います。あとは、use_case が Trait になっていないので、モックが作りづらいとかはあるかなあと思います。

ただ、コードは、(私的にはですが)割とシンプルな感じなので、シンプルさ的にはいいかなあと思っています。

ただ、リポジトリに渡しているのが、DB Pool なので、リポジトリの関数を実行する度に Pool からコネクションをとってきていると思います。これが、今回の Rocket のバージョンとの違いかなあと思っております。

毎回関数実行時に connection を取得・破棄するというのは、1 リクエストで同じ connection を使い続ける場合と比べて、相対的に非効率になるのかなと思ってます。(計測したりしていませんが、ChatGPT に聞いたら、そうだよ、と言っていました)また、トランザクションも基本的には repository 関数内で完結させるしかないので、複数の repository をまたいだり、外部サービスのレスポンスを待ってから commit したりということが、基本できない(ややこしい)のかなと思っています。

今回作った Rocket バージョンのリポジトリ

今回の Rocket バージョンのリポジトリが下記です。よかったらスターをお願いします!

https://github.com/edo1z/rust-rocket-sqlx-sample

特徴

  • use_case も repository も Trait にしたので、モックが作りやすくなりました。
  • repository の各関数に渡すのは、DB Pool から取得したコネクションの参照になっていますので、上記の Axum バージョンより、ちょっと効率がよいのではないか?と思っています。
    • 1 リクエスト毎に Pool からコネクションを取得して、同じリクエスト内ではずっとそのコネクションを使います。リクエストの処理が終わったら返却(破棄)されます。
  • repository の各関数に connection を渡しますので、use_case 側でトランザクションを作って、複数の repository 関数の実行後に commit させるというのも、やろうと思えばできます。
  • controller, use_case, repository(統合テスト)が簡単に出来るようになっています。

悩ましかった点

  • トランザクションの扱い
    • Transaction PoolConnection の両方を受け取れる repository 関数を使いながら mockall.automock を使うのが難しかった(結局両方受け取れる関数にするのをやめた)
    • 上記の結果、repository のテスト時に Transaction の Rollback を使ってテーブル状態をクリアするというのが使えなくなった。(今はテスト前に truncate している)
  • Axum バージョンと比べると DB コネクション周りのコードが若干シンプルではなくなった。
    • まあでも関数に Pool を渡すと非効率だし、トランザクションも使いづらいのでよいのかなと思いました。

将来やりたいこと

  • SeaORM を導入したい。
  • テストでトランザクションを簡単に使えるようにしたい。
  • 現在、Rocket の sqlx は 0.6 ですが、SeaORM は 0.7 です。もしかしたら、Rocket の db 関連ライブラリを使うのをやめるかも。

まとめ

  • Axum も Rocket もいい感じだと思いました
  • トランザクションややこしいと思いました
  • よかったらリポジトリ のスターをお願いします!
Rust🦀, Network⚡, PostgreSQL🐘, Unity🎮

Tags

rust  (9)
rocket  (7)
svelte  (5)
c++  (4)
ethereum  (3)
solidity  (3)
vscode  (3)
sqlx  (3)
glfw  (2)
opengl  (2)
nestjs  (2)
graphql  (2)
render  (2)
wsl2  (2)
truffle  (1)
goerli  (1)
geth  (1)
hardhat  (1)
nft  (1)
gui  (1)
tetris  (1)
next.js  (1)
jwt  (1)
nextauth  (1)
node.js  (1)
prisma  (1)
passport  (1)
urql  (1)
codegen  (1)
mdsvex  (1)
markdown  (1)
tmux  (1)
nvim  (1)
axum  (1)
atcoder  (1)
vim  (1)
pacman  (1)
tracing  (1)
Cursor  (1)
VSCode  (1)
PHP  (1)
Laravel  (1)