【クリーンアーキテクチャ×FastAPI】ファイル・フォルダ構成について考える。
こんにちは、にわこまです!
今回は、クリーンアーキテクチャを採用したFastAPIアプリケーションのファイル・フォルダ構成について考えてみました。
最近は、生成AIにソースコードを作成させることがほとんどだと思います。その際のインプットとしていただくことでより精度の高いソースコードが生成されるのではないかと思います。
ぜひ参考にしてみてください。
スポンサードサーチ
ファイル・フォルダ構成
Googleスプレッドシートに一覧をまとめています。
ファイル・フォルダ構成
自由にダウンロードしていただいて問題ないです。
src
├─ application
│ ├─ usecases
│ ├─ dto
│ ├─ mappers
│ ├─ interfaces
│ ├─ transaction
│ │ └─ unit_of_work.py
│ └─ exceptions
├─ domain
│ ├─ entities
│ ├─ value_objects
│ ├─ services
│ ├─ exceptions
│ └─ constants
├─ infrastructure
│ ├─ database
│ │ ├─ common
│ │ │ └─ retry_manager.py
│ │ └─ xxx
│ │ ├─ repositories
│ │ ├─ models
│ │ ├─ session.py
│ │ ├─ engine.py
│ │ ├─ mappers
│ │ └─ transaction.py
│ ├─ external
│ │ ├─ common
│ │ │ └─ retry_manager.py
│ │ └─ xxx
│ │ ├─ client.py
│ │ ├─ dto
│ │ │ ├─ xxx.py
│ │ │ └─ yyy.py
│ │ └─ mapper.py
│ └─ messaging
│ ├─ xxx_producer.py
│ ├─ xxx_consumer.py
│ └─ yyy_producer.py
├─ presentation
│ ├─ routers
│ ├─ requests
│ ├─ responses
│ ├─ mappers
│ ├─ exception_handlers
│ └─ deps.py
├─ shared
│ ├─ exceptions
│ ├─ logging
│ ├─ config
│ └─ utils
└─ main.py
前提
- 使用言語が Python であること。
- REST API アプリケーションであること。
- 実処理では、DBとのやり取りや他サービスとのやり取りを想定すること。
- 小規模から中規模であること。※多くとも20APIくらい。
- クリーンアーキテクチャを採用すること。特に依存性の方向を守ること。以下、図に示す。
- FastAPIを採用すること。
依存性の方向
flowchart TB
Presentation["Presentation"]
Application["Application"]
Domain["Domain"]
Infrastructure["Infrastructure"]
Presentation --> Application
Application --> Domain
Infrastructure --> Application
Infrastructure --> Domain
style Presentation fill:#A2FDBA
style Application fill:#FFA09C
style Domain fill:#FCFDB9
style Infrastructure fill:#A7D7FD| 自分\相手 | Presentation | Application | Domain | Infrastructure |
| Presentation | – | 依存する。 | 依存しない。 | 依存しない。 |
| Application | 依存しない。 | – | 依存する。 | 依存しない。 |
| Domain | 依存しない。 | 依存しない。 | – | 依存しない。 |
| Infrastructure | 依存しない。 | 依存する。 | 依存する。 | – |
- Presentation層はApplication層に依存する。
- Application層はDomain層に依存する。
- Domain層は他の層に依存しない。
- Infrastructure層はApplication層(interfaces)に依存する。
- Infrastructure層はDomain層に依存する。
責務
| 層 | 責務 | 説明 |
|---|---|---|
| Presentation | HTTPの責務 | エンドポイント、リクエストボディ、レスポンスボディを定義する。Open APIに記載した内容を定義するイメージ。 |
| Application | 業務フローの責務 | 何をどの順番で実行するか定義する。 |
| Domain | 業務ルールの責務 | 他技術に依存しない業務に関するデータや処理を定義する。 |
| Infrastructure | 技術的実装の責務 | データベースやREST API、Kafkaなどの外部との連携を定義する。 |
| Shared | アプリ内共通、業務仕様に依存しない | ロガーや定数を定義する。他の層から共通的に使用される処理を定義する。 |
Presentation
エンドポイント、リクエストボディ、レスポンスボディを定義する。
| ファイル・フォルダ | 責務 | 説明 |
|---|---|---|
| presentation/routers | ルータの実装 | Open APIの仕様に基づきエンドポイントを定義し、UseCaseを呼び出す。 |
| presentation/requests | リクエストボディの定義 | Open APIの仕様に基づきリクエストボディを定義し、バリデーションを行う。 |
| presentation/responses | レスポンスボディの定義 | Open APIの仕様に基づきレスポンスボディを定義する。 |
| presentation/mappers | データの変換 | リクエストボディやレスポンスボディをApplicaiton層のDTOに変換する処理を実装する。 |
| presentation/exception_handlers | 例外のハンドリング | Application層の例外やDomain層の例外をHTTPレスポンスへ変換する。 |
| presentation/deps.py | DIの実装 | UseCaseやRepositoryなどの依存関係を解決し、オブジェクトを組み立てる。 |
Application
何をどの順番で実行するか定義する。
| ファイル・フォルダ | 責務 | 説明 |
|---|---|---|
| application/usecases | ユースケースの実装 | 業務処理の流れを実装する。トランザクション境界の管理やRepositoryの呼び出しを行う。 |
| application/dto | DTOの定義 | Application層で使用するデータクラスを定義する。 |
| application/mappers | データの変換 | Application層のDTOからDomain層のEntityに変換する処理を実装する。 |
| application/interfaces | インターフェースの定義 | Infrastructure層が実装するRepositoryや外部サービスClientのインターフェースを定義する。 |
| application/transaction/unit_of_work.py | UnitOfWorkの実装 | 複数RepositoryのCommitやRollbackを管理し、トランザクション境界を提供する。 |
| application/exceptions | 例外の定義 | UseCaseで発生する業務処理上の例外を定義する。 |
Domain
他技術に依存しない業務に関するデータや処理を定義する。
| ファイル・フォルダ | 責務 | 説明 |
|---|---|---|
| domain/entities | エンティティの定義 | 一意性を持つ業務オブジェクトを定義する。状態遷移や業務ルールを保持する。 |
| domain/value_objects | 値オブジェクトの定義 | 不変オブジェクトを定義する。入力値の妥当性や業務上の制約を保証する。 |
| domain/services | サービスの実装 | 特定のEntityやValue Objectだけでは表現できない業務ロジックを実装する。 |
| domain/exceptions | 例外の定義 | 業務ルール違反や不正な状態を表す例外を定義する。 |
| domain/constants | 定数の定義 | 状態値や業務ルール、Domain層で使用する定数を定義する。 |
Infrastructure
データベースやREST API、Kafkaなどの外部との連携を定義する。
| ファイル・フォルダ | 責務 | 説明 |
|---|---|---|
| infrastructure/database | データベース関連の機能を定義 | データベースとの接続や永続化処理を実装する。 |
| infrastructure/database/common | 共通機能を定義 | 複数データベースで共通利用する技術的な機能を定義する。 |
| infrastructure/database/common/retry_manager.py | リトライ機能を定義 | デッドロックや一時的な接続障害などに対するリトライ処理を実装する。 |
| infrastructure/database/xxx | 個別のデータベース関連の機能を定義 | 接続先データベースごとの機能を実装する。 |
| infrastructure/database/xxx/repositories | リポジトリの実装 | Application層で定義したRepositoryインターフェースを実装する。 |
| infrastructure/database/xxx/models | テーブルを定義 | SQLAlchemy等で使用するORMモデルやテーブルを定義する。 |
| infrastructure/database/xxx/session.py | セッション管理機能を定義 | SQLAlchemy Sessionの生成・取得・破棄など、セッションライフサイクルを定義する。 |
| infrastructure/database/xxx/engine.py | データベース接続の実装 | SQLAlchemy Engineの生成や接続プール設定など、DB接続設定を定義する。 |
| infrastructure/database/xxx/mappers | データの変換 | Domain層EntityとDB Modelの相互変換を実装する。 |
| infrastructure/database/xxx/transaction.py | トランザクション管理機能を定義 | トランザクション開始・コミット・ロールバックなどの制御を実装する。 |
| infrastructure/external | 外部サービス連携の機能を定義 | 外部サービスとのHTTP通信を実装する。 |
| infrastructure/external/common | 共通の定義 | 外部サービス共通で利用する技術的な機能を定義する。 |
| infrastructure/external/common/retry_manager.py | リトライ機能を定義 | タイムアウトや一時的な通信障害などに対するリトライ処理を実装する。 |
| infrastructure/external/xxx | 個別サービス関連の機能を定義 | 外部サービスごとの機能を実装する。 |
| infrastructure/external/xxx/client.py | APIクライアントの定義 | HTTP通信を定義する。 |
| infrastructure/external/xxx/dto | DTOの定義 | 外部サービスとの通信で使用するDTOを定義する。 |
| infrastructure/external/xxx/dto/xxx.py | APIごとのDTOの定義 | XXX APIのリクエストボディやレスポンスボディを定義する。 |
| infrastructure/external/xxx/dto/yyy.py | APIごとのDTOの定義 | YYY APIのリクエストボディやレスポンスボディを定義する。 |
| infrastructure/external/xxx/mapper.py | データの変換 | Domain層のEntityと外部API DTOの相互変換を行う。外部APIの仕様変更をDomain層へ波及させない責務を持つ。 |
| infrastructure/messaging | Kafka関連の機能を定義 | Kafkaの送受信機能を実装する。 |
| infrastructure/messaging/xxx_producer.py | TopicごとのProduerを定義 | XXX TopicのProducerを実装する。 |
| infrastructure/messaging/xxx_consumer.py | TopicごとのConsumerを定義 | XXX TopicのConsumerを実装する。 |
| infrastructure/messaging/yyy_producer.py | TopicごとのProduerを定義 | YYY TopicのProduserを実装する。 |
xxxやyyyは、データベースごとやAPIごと、Topicごとを表現しています。
上記ファイル・フォルダ構成には記載していませんが、messagingフォルダ配下にdtoやmappersがあってもよいと思います。以下にイメージを示します。
messaging
├─ xxx_producer.py
├─ xxx_consumer.py
├─ yyy_producer.py
├─ dto
└─ mappers
Shared
ロガーや定数を定義する。他の層から共通的に使用される処理を定義する。
| ファイル・フォルダ | 責務 | 説明 |
|---|---|---|
| shared/exceptions | 共通例外 | 共通利用する例外クラスを定義する。 |
| shared/logging | Loggerの管理 | Loggerの設定を定義する。 |
| shared/config | 設定値の管理 | 環境変数の読み込みや共通的に使用する定数を定義する。 |
| shared/utils | 共通ユーティリティ | 日付変換や文字列操作などの共通処理を実装する。 |
main.py
| ファイル・フォルダ | 責務 | 説明 |
|---|---|---|
| main.py | アプリケーションの起点 | FastAPI起動。Exception Handlerの設定。Lifespanの設定。Routerの登録。 |
まとめ
今回は、クリーンアーキテクチャを採用したFastAPIアプリケーションのファイル・フォルダ構成について考えてみました。
ここまで考えてみて、FastAPIである必要性はないなと思いました笑。Flaskでも問題ないと思いました。
Googleスプレッドシートに一覧をまとめています。
ファイル・フォルダ構成
自由にダウンロードしていただいて問題ないです。
かなり、具体例を示せたと思っています。ゆえに、ご自身の既存のファイル・フォルダ構成と異なる点があると思います。
その際は、メールまたはX(Twitter)でご意見いただければと思います。
最後までお読みいただきありがとうございます。
スポンサードサーチ
