0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

TypeScript×クリーンアーキテクチャで簡単なタスク管理アプリを作成した

Posted at

n 番煎じかもしれませんがクリーンアーキテクチャについての学習のアウトプットも兼ねて TypeScript で簡単なタスク管理アプリケーションを作成しました。

使用技術

ディレクトリ構成

上層レイヤから infrastructure, presentation, application, domain の順

./src
├── application  // アプリケーション層。ユースケースを定義し、DTO を使用してデータの転送を管理。
│   ├── dtos  // データ転送オブジェクトを格納するディレクトリ
│   │   └── TaskDTO.ts
│   └── useCases  // ユースケースを定義するディレクトリ
│       ├── CreateTask.ts
│       ├── DeleteTask.ts
│       ├── FindAllTasks.ts
│       ├── FindTaskById.ts
│       └── UpdateTask.ts
├── domain  // ドメイン層。ビジネスロジックやルールを定義。
│   ├── entities  // ドメインエンティティを格納するディレクトリ
│   │   └── Task.ts
│   ├── errors  // エラー管理を行うためのクラスを格納するディレクトリ
│   │   ├── DatabaseError.ts
│   │   ├── UnknownError.ts
│   │   └── ValidationError.ts
│   ├── repositories  // リポジトリインターフェースを定義するディレクトリ
│   │   └── TaskRepository.ts
│   └── services  // ドメインサービスを定義するディレクトリ
│       └── TaskService.ts
├── index.ts  // アプリケーションのエントリーポイント
├── infrastructure  // インフラ層。外部システムとのやり取りを管理。
│   └── repositories  // リポジトリの実装を格納するディレクトリ
│       └── Prisma  // Prisma を使用したリポジトリの実装
│           └── PrismaTaskRepository.ts
└── presentation  // プレゼンテーション層。ユーザーとのインターフェースを管理。
    ├── controllers  // コントローラーを格納するディレクトリ
    │   ├── BaseController.ts
    │   └── TaskController.ts
    └── routes  // ルーティングを定義するディレクトリ
        └── taskRoutes.ts


リポジトリ実装のエラーハンドリング

リポジトリ実装で例えば Prismanode-postgres 等のパッケージに依存したエラーをそのまま投げてしまうと、内側の層が一番外側の infrastructure 層に依存するという依存性の逆転が発生してしまいます。そのためリポジトリ実装で発生したエラーは domain 層で定義したカスタムエラーに変換することで依存性の逆転が発生しないようにしました。

export class PrismaTaskRepository implements TaskRepository {
  constructor(private readonly client: PrismaClient) {}

  private handlePrismaError(e: unknown): Error {
    // エラー内容をログに残す
    console.error(e);
    // Prisma ORM に依存したエラーをカスタムエラーに変換
    if (e instanceof PrismaClientValidationError)
      return new ValidationError(e.message);
    if (e instanceof PrismaClientKnownRequestError)
      return new DatabaseError(e.message);
    if (
      e instanceof PrismaClientUnknownRequestError ||
      e instanceof PrismaClientRustPanicError
    )
      return new UnknownError(
        "An unknown error occurred while trying to fetch tasks",
      );

    return new UnknownError(
      "An unknown error occurred while trying to fetch tasks",
    );
  }

  async findAll() {
    try {
      const tasks = await this.client.task.findMany();
      return tasks.map((task) => new Task(task));
    } catch (e) {
      // エラーハンドリング
      throw this.handlePrismaError(e);
    }
  }

  // 以下省略
}

おまけ

Hono

本筋とは逸れますが今回採用した Web フレームワーク Hono は Web 標準に準拠しています。そのため Web 標準の Request, Response, etc... を利用したコントローラを容易に作成することができました。例えば有名な Web フレームワークである Express では独自の Request や Response を採用しているため、それらを利用したコントローラを作成してしまうとフレームワークを変更した際にコントローラの実装も大きく変更する必要が出てくるかもしれません。

参考

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?