Chapter 11無料公開

✅Usecaseは1つのトランザクションを管理する

たった
たった
2021.06.25に更新
このチャプターの目次
アプリケーションコード
src
├── middleware     ... 認証・認可とGraphQLのコンテキスト
├── domain         ... ビジネスロジックの共通化
>├── usecases       ... アプリケーションロジック
├── infrastructure ... 外部サービスとのやりとり
├── entities       ... エンティティとGraphQLのフィールド
├── resolvers      ... GraphQLのリゾルバー
└── inversify.config.ts ... 依存性の注入(以下、DI)の設定

このチャプターで使用するライブラリ

  • TypeORM
  • InversifyJS

概要

UsecaseはClean Architectureの「Usecase」、ドメイン駆動設計の「サービス」に該当するモジュールです。

基本的にはこれらの概念に沿って設計するわけですが、このチャプターで強調したいのは、1つのユースケースが1つのトランザクションを管理するという役割です。
逆に言えば、Usecase以外にトランザクションを管理するモジュールは存在しません。(トランザクションを使う必要がないユースケースもあります。)

これによって、ユースケースの不可分性を保証することができます。

では先程のチャプターと同様、以下の仕様を追加することにした場合のユースケースの実装を見ていきましょう。

  • ユーザを作成する
    • リクエストしてきたユーザを新しいユーザとして登録する

実装

Usecaseでは、ConnectionDomainを注入します。
以下のようにトランザクションを貼ってDomainにトランザクションのマネージャを渡しましょう。

be/src/usecases/UserUsecase.ts
@injectable()
export class UserUsecase {
  constructor(
   @inject(Connection) private readonly conn: Connection
   @inject(UserDomain) private readonly domain: UserDomain
  ) {}

  public async addUsers(
    inputs: UserAddVo[]
  ) {
    const qR = this.conn.createQueryRunner()
    qR.connect()
    qR.startTransaction()
    try {
      const users = await Promise.all(
        inputs.map(vo) => await this.domain.addUser(qR.manager, vo)
      )
      await qR.commitTransaction()
      await qR.release()
      return users
    } catche (e) {
      await qR.rollbackTransaction()
      await qR.release()
      throw new Error(e)
    }
  }
}

Domainでは与えられたマネージャを使って処理を行います。Domainで行われる処理は次のチャプターで解説します!