A Python implementation of Clean Architecture, inspired by Uncle Bob's book
This is an example of implementing a PokΓ©mon API based on the Clean Architecture in a Python project, using the FastAPI framework.
v1: Check out the v1 branch.
Archived in April 2021.
Description: Initial proposal by me.
v2: Check out the v2 branch.
Archived in July 2023.
Description: Improvement from v1 were inspired by the v3 branch of the go-clean-arch. See the merged PRs from PR #1 to PR #10.
βοΈ v3: Current version on the master
branch.
Merged to main in August 2023 and still evolving.
Description: Transition to Python-centric design from Go. Start with PR #11 and see all subsequent PRs.
The Clean Architecture, popularized by Uncle Bob, emphasizes several foundational principles:
*source: yoan-thirion.gitbook.io
This project not only adheres to Uncle Bob's Clean Architecture principles but also incorporates modern adaptations and extended features to meet contemporary development needs:
entrypoints
module contains two API interfaces. graphql
provides for a robust GraphQL API, while http
focuses on RESTful API routes and controls.repositories
module supports both relational databases (e.g., SQLite, MySQL, PostgreSQL) and NoSQL databases, including document-oriented stores (e.g., MongoDB, CouchDB) and key-value stores (e.g., Redis, Memcached).Apart from following Uncle Bob's Clean Architecture, this project also incorporates:
Based on Uncle Bob's Clean Architecture principles, this project's structure and architecture flow diagrams are aligned with these principles.
Here's a glimpse of the project's high-level structure, highlighting primary directories and key files:
./
βββ ...
βββ src/
β βββ di/ - Dependency injection configurations for managing dependencies.
β β βββ dependency_injection.py
β β βββ unit_of_work.py
β β
β βββ entrypoints/ - External interfaces like HTTP & GraphQL endpoints.
β β βββ graphql/ - GraphQL components for a flexible API.
β β βββ http/ - RESTful API routes and controllers.
β β ('Frameworks and Drivers' and part of 'Interface Adapters' in Clean Architecture)
β β
β βββ usecases/ - Contains application-specific business rules and implementations.
β β ('Use Cases' in Clean Architecture)
β β
β βββ repositories/ - Data interaction layer, converting domain data to/from database format.
β β βββ relational_db/ - Operations for relational databases (e.g., SQLite, MySQL, PostgreSQL).
β β βββ document_db/ - Operations for document-oriented databases (e.g., MongoDB, CouchDB).
β β βββ key_value_db/ - Operations for key-value databases (e.g., Redis, Memcached).
β β ('Interface Adapters' in Clean Architecture)
β β
β βββ models/ - Domain entities representing the business data.
β β ('Entities' in Clean Architecture)
β β
β βββ common/ - Shared code and utilities.
β βββ settings/
β β βββ db/ - Database configurations.
β β ('Frameworks and Drivers' in Clean Architecture)
β β
β βββ main.py - Main file to launch the application.
β
βββ tests/
βββ api_db_test.bats - BATs tests for API and database interactions.
βββ integration/ - Integration tests for testing module interactions.
βββ unit/ - Unit tests for testing individual components in isolation.
The Clean Architecture Flow Diagram visualizes the layers of Clean Architecture and how they interact. It consists of two images and an ASCII flow for clarity:
For a detailed explanation of the ASCII flow, refer to ascii-flow.md.
*source: yoan-thirion.gitbook.io
*source: https://stackoverflow.com/a/73788685
Here's everything you need to get this project running on your local machine for development and testing.
This application is designed to support multiple databases. Choose one of the following setups:
The application will default to using an In-Memory SQLite database if no DATABASE_URI
is specified.
For utilizing other databases, Docker Compose can be employed:
$ docker compose down --remove-orphans -v
$ docker compose up dockerize
DATABASE_URI
environment variable is set appropriately.Supported Database URIs::
sqlite+aiosqlite:///<dbname>.db
(SQLite)sqlite+aiosqlite:///:memory:
(In-Memory SQLite)mysql+asyncmy://<username>:<password>@<host>:<port>/<dbname>
(MySQL)postgresql+asyncpg://<username>:<password>@<host>:<port>/<dbname>
(PostgreSQL)mongodb://<username>:<password>@<host>:<port>/<dbname>
(MongoDB)redis://<username>:<password>@<host>:<port>/<dbname>
(Redis)π Note: If encountering issues with database initialization, consider appending
reinitialize=true
to theDATABASE_URI
for reconfiguration, e.g.,sqlite+aiosqlite:///sqlite.db?reinitialize=true
.
To run the application inside a Docker container:
$ DATABASE_URI=<database-uri> docker compose up app
Ensure Python (version 3.10 or higher) and Poetry (version 1.8.x) are installed.
Configure your environment: [^6]
$ poetry env use python3.10
$ poetry shell
$ poetry install
Launch the application:
$ DATABASE_URI=<database-uri> make up
After setup, access the application at http://localhost:8000.
To conduct tests against a single database, specify its URI by configuring the DATABASE_URI
environment variable:
$ DATABASE_URI=<database-uri> pytest
For the list of supported database URIs, please refer to the Supported Database URIs
π Note: For testing, it's recommended to use a different
dbname
, preferably with a "_test" suffix (e.g., "mydatabase_test"). This ensures your tests don't interfere with your main application data.
To validate your application across various databases like In-Memory SQLite, SQLite, MySQL, Postgres and MongoDB, you'll utilize the tool called bats
.
Installing bats
- On macOS: use Homebrew
$ brew install bats
- On Linux: compile from the official GitHub repository
$ git clone https://github.com/bats-core/bats-core.git
$ cd bats-core
$ ./install.sh /usr/local
Running Multi-DB Tests
$ make test
api_db_test.bats
β Test using SQLite [3136]
β Test using In-Memory SQLite [2399]
β Test using MySQL [3615]
β Test using PostgreSQL [3437]
β Test using MongoDB [4099]
5 tests, 0 failures in 18 seconds
To demonstrate best practices and emphasize the importance of thorough testing, we've integrated pytest-cov
to monitor our test coverage. [^5]
To generate a coverage report:
$ pytest --cov
A simple β can go a long way in showing your appreciation!
[^5]: The coverage rate for this 'py-clean-arch' project stands at 91.33%, based on test results from August 20, 2023.
[^6]: The poetry install
command installs all required packages for running and developing the application. However, it does not include cspell
. If you need cspell
for spell checking, please refer to the official installation guide at cspell installation guide