キカガク プラットフォームブログ

株式会社キカガクのプラットフォームブログです。エンジニアやデザイナー、プロダクトマネージャーなどが記事を書いています。

NestJS で Prisma やトランザクションを考慮しながらドメイン駆動設計をする

プラットフォーム部の dascarlet です。 今回は、NestJS で Prismaトランザクションを考慮しながらドメイン駆動設計をする方法について紹介します。

進行中のプロジェクト内の話にあたるので具体的なコードはご紹介できませんが参考になれば幸いです。

NestJS とドメイン駆動設計、そして Prismaトランザクション

弊社では NestJSドメイン駆動開発を用いてバックエンドの開発が進行中です。RDB へのアクセスは Prisma を利用しています。そんな中で問題となったのは「ドメイン駆動設計を維持しながら Prisma を用いてトランザクションRDB へ走らせる」ということをどのように実現するか、でした。

Prisma$transaction API からは二種類の書き方が提供されています。一見すると事足りるように見えるのですがドメイン駆動設計やリポジトリパターンと共に使用しようとすると、複数のドメインを扱ったトランザクションを実行するときに Prisma の表現力の都合上どうしても不都合が出てくる部分があります。

これを解決するために Node.js APIAsyncLocalStorage をラップしている NestJS CLS というライブラリを利用し、更に TransactionModuleNestJS 上に用意しました。以下が簡単な図になります。

説明

例えばある ApplicationServiceModule の Provider に登録されている XXXApplicationServiceYYYRepositoryZZZRepository を用いてトランザクションを張りながらCRUD操作を行いたいとします。その場合 TransactionModule が提供する inTransaction() という関数に YYYRepository,ZZZRepository の関数を実行するコールバック関数を渡せば、その後は PrismaServiceModuleトランザクションを考慮しながら上手くコールバック関数を実行してくれるという仕組みになっています。

その際、各 Repository からは「トランザクション専用で同一な Prisma の Client インスタンス」が利用されなければなりません。上記で紹介した NestJS CLS をラップした RequestContextModule がその部分を担当しています。

YYYRepositoryZZZRepositoryドメインを合体させた YYZZRepository などを作るのも手ですが、様々なドメインが追加される度に組み合わせがどんどん増えていってしまうのでその方法は見送りました。

短い記事にはなりましたが同じような問題に直面した方の参考になれば幸いです。

参考(大変参考になり感謝しています)