This project provides a robust and flexible template for building REST APIs with FastAPI, following a clean architecture inspired by Domain-Driven Design (DDD) principles. It includes a structured approach to organizing business logic, handling routing, and managing dependencies, along with pre-configured tools for development and testing.
- Features
- Architecture Overview
- Getting Started
- Project Structure
- Code Generation (Blueprints)
- Pre-commit Hooks
- Database
- Authentication
- Error Handling
- Contributing
- License
- FastAPI: High-performance, easy-to-use web framework.
- SQLModel: Type-based ORM for SQL databases, built on SQLAlchemy and Pydantic.
- Poetry: Dependency management and packaging.
- Docker Compose: Easy setup for PostgreSQL database.
- Clean Architecture: Clear separation of concerns (Controllers, Use Cases, Repositories).
- Dependency Injection: Managed using FastAPI's
Dependsfor clear dependency graphs. - JWT Authentication: Secure user authentication with access tokens.
- Pre-commit Hooks: Automated code formatting (Black, Ruff), type checking (MyPy), and tests.
- Health Check Endpoint: Basic API health status.
- GZip Middleware: Compresses responses for faster delivery.
- CORS Middleware: Configured for cross-origin resource sharing.
- Blueprint: Templates for quick generation of new route modules.
This project adheres to a clean architecture, as documented in docs/adrs/project_structure.md, promoting maintainability, testability, and scalability.
The core business logic is organized into the following layers:
- Controller: Handles incoming requests, validates input DTOs (Data Transfer Objects), and orchestrates the call to the appropriate Use Case. It acts as the entry point for API routes.
- UseCase: Encapsulates the application's business rules and logic. Each Use Case performs a specific task and interacts with repositories to fetch or persist data. They are designed to be independent of external frameworks.
- Repository: Manages communication with the database. Repositories provide an abstraction over data storage, allowing Use Cases to interact with data without knowing the underlying database implementation. They are defined by Protocols to facilitate unit testing and ensure loose coupling.
Order of Consumption:
Controller -> UseCase -> Repository (via UseCase)
Repositories are not consumed directly by Controllers; they are injected into Use Cases.
The routing system is structured hierarchically:
- General Router: The main
APIRouterthat includes fundamental routes (e.g., health check) and version-specific routers. (src/fast_api_template/core/infra/base_router.py) - Version Router: Routers for API versioning (e.g.,
v1,v2). This allows for managing API changes gracefully. (src/fast_api_template/infra/v1_router.py) - Module Router: Routers specific to a particular module or domain (e.g.,
UserRouter,AccountRouter). These contain the individual API endpoints for that module. (src/fast_api_template/modules/user/v1/infra/user_router_v1.py)
Middlewares are located in the src/fast_api_template/modules/shared/middlewares directory. They are designed to perform global tasks that affect all incoming requests or outgoing responses, such as:
- CORS (Cross-Origin Resource Sharing): Configured to allow requests from any origin.
- GZip Compression: Automatically compresses responses for requests above a certain size, improving performance.
- Process Time Header: Adds an
X-Process-Timeheader to responses, indicating how long it took to process the request.
Important Note: Middlewares do not share information directly with controllers. Any shared information or dependencies should be passed via FastAPI's dependency injection system. This ensures that middlewares focus solely on global concerns, while authentication and authorization logic reside within the application's core or specific use cases, often utilizing dependency injection for user validation.
Utility functions, which solve simple, recurring problems across multiple modules, are stored in the src/fast_api_template/modules/shared/utils directory. Examples include cryptographic functions (crypto.py) for hashing and JWT handling.
Follow these steps to set up and run the project locally.
Before you begin, ensure you have the following installed:
- Python 3.10+: The project is built with Python 3.10.
- Poetry: A Python dependency management and packaging tool. If you don't have it, install it with:
pip install poetry
- Docker and Docker Compose: Required for running the PostgreSQL database.
-
Clone the repository:
git clone <your-repository-url> cd fast-api-template
-
Install project dependencies using Poetry:
poetry install
This command will create a virtual environment and install all the dependencies listed in
pyproject.toml. -
Install pre-commit hooks:
poetry run pre-commit install
This sets up hooks that will run automatically before each commit, ensuring code quality and consistency.
-
Start the database container:
docker-compose up -d db
This will start a PostgreSQL database container in the background, as defined in
docker-compose.yml. The database will be accessible on port5432.
The project uses pydantic-settings to manage environment variables. You need to create a .env file in the root of your project.
Example .env file:
POSTGRES_URL="postgresql+asyncpg://admin:admin@localhost:5432/template"
SALT="your_strong_salt_string"
PEPPER="your_strong_pepper_string"
SECRET="your_jwt_secret_key"
JWT_TTL=3600 # JWT Time-To-Live in seconds (e.g., 1 hour)Important:
- Replace
your_strong_salt_string,your_strong_pepper_string, andyour_jwt_secret_keywith actual strong, randomly generated values. You can generate these using tools or Python'ssecretsmodule. - The
POSTGRES_URLshould match your database configuration. If using the provideddocker-compose.yml, the URLpostgresql+asyncpg://admin:admin@localhost:5432/templateis correct.
To start the FastAPI development server:
poetry run devThis command will run uvicorn with src/fast_api_template.core.main:app, listening on http://127.0.0.1:8000 and enabling auto-reload for development.
You can then access the API documentation (Swagger UI) at http://127.0.0.1:8000/docs.
To execute the project's tests:
poetry run pytestThe pytest.ini file configures asyncio_mode=auto for seamless testing of asynchronous code.
The project follows a modular structure, with each major component or domain residing in its own module:
.
├── blueprints/ # Templates for generating new modules/routes
├── docs/ # Project documentation (ADRs, etc.)
│ └── adrs/
├── scripts/ # Utility scripts (e.g., dev server runner)
├── src/
│ └── fast_api_template/
│ ├── core/ # Core application components
│ │ ├── infra/ # Infrastructure (database, routers, env)
│ │ ├── middlewares/ # Global FastAPI middlewares
│ │ └── main.py # FastAPI application entry point
│ ├── infra/ # Versioning routers (e.g., v1_router)
│ ├── modules/ # Main application modules/domains
│ │ ├── health_check/ # Example module: API health check
│ │ │ ├── infra/
│ │ │ └── use_cases/
│ │ │ └── health_check/
│ │ ├── shared/ # Shared components across modules
│ │ │ ├── base_dto.py
│ │ │ ├── base_model.py
│ │ │ ├── base_use_case.py
│ │ │ ├── dependency_injections/ # Common dependency injections
│ │ │ ├── middlewares/ # Shared middlewares
│ │ │ └── utils/ # Utility functions (e.g., crypto)
│ │ └── user/ # Example module: User management
│ │ ├── repository/
│ │ │ └── schemas/
│ │ ├── v1/ # Versioned API for User module
│ │ │ └── features/ # Features/sub-domains within the module
│ │ │ ├── create_user/
│ │ │ ├── delete_me/
│ │ │ ├── get_me/
│ │ │ └── login/
│ │ └── user.py # User ORM model
├── .env.example # Example environment variables file
├── .pre-commit-config.yaml # Pre-commit hook configurations
├── docker-compose.yml # Docker Compose setup for services
├── pyproject.toml # Poetry project configuration and dependencies
├── pytest.ini # Pytest configuration
└── README.md # Project README
The blueprints/route/ directory contains templates that can be used to quickly scaffold new routes/features within your modules. These templates include:
{{file_name}}_controller.py.template{{file_name}}_dto.py.template{{file_name}}_injection.py.template{{file_name}}_use_case.py.template
These templates are designed to follow the established architecture (Controller, DTO, Injection, UseCase). You would typically use a custom script or a tool like blprint (which is a dependency of this project) to generate new modules from these templates, replacing the {{variable}} placeholders with your desired names (e.g., {{name__snake_case}}, {{name__camel_case}}).
Example of blprint usage (assuming blprint is installed and configured):
To create a new product module feature within v1:
blueprint create route ./src/fast_api_template/modules/product/v1/features/(Note: You might need to adjust the blueprint command based on its exact configuration for this project.)
This project uses pre-commit to maintain code quality and consistency. The .pre-commit-config.yaml file defines the following hooks:
- Black: An uncompromising Python code formatter.
- MyPy: A static type checker for Python. It checks for type consistency across your codebase.
- Ruff: An extremely fast Python linter, written in Rust.
end-of-file-fixer: Ensures files end with a newline.trailing-whitespace: Removes superfluous whitespace at the end of lines.check-merge-conflict: Checks for files that contain merge conflict strings.pytest-check: Runs all tests before each commit, preventing commits that break existing functionality.
These hooks run automatically when you commit your changes, helping to catch issues early in the development cycle.
The project uses SQLModel as its ORM, providing a type-hinted way to interact with SQL databases. The docker-compose.yml file sets up a PostgreSQL database.
dbservice: Runs apostgres:15image.- Environment Variables: Configured with
POSTGRES_USER,POSTGRES_PASSWORD, andPOSTGRES_DBset toadmin,admin, andtemplaterespectively. Remember to change these credentials in production environments. - Port Mapping: The database is exposed on port
5432of your host machine. - Volume: A named volume
pgdatais used to persist database data, so your data won't be lost when the container is stopped or removed.
The create_db_and_tables() function in src/fast_api_template/core/infra/database.py is called during the application's lifespan event to automatically create all defined SQLModel tables if they don't already exist.
The project includes a basic JWT-based authentication system:
require_user_injection.py: ProvidesGetCurrentUseras a FastAPI dependency. This dependency decrypts a JWT token from theAuthorizationheader, validates its expiration, and retrieves the correspondingUserfrom the database. If the token is invalid or expired, it raises anHTTPException.login_controller.py: Handles user login, authenticating credentials and issuing a JWT token.crypto.py: Contains utility functions for hashing passwords (hash_string) and encrypting/decrypting JWT payloads (encrypt_payload,decrypt_jwt).Usermodel: Defines the user schema with email and hashed password.
The project currently has a TODO to improve error handling, specifically for login and user creation errors. While some basic HTTPException are raised (e.g., for duplicate emails or invalid tokens), a more comprehensive global error handling strategy could be implemented (e.g., custom exception handlers for specific error types or a centralized error response format).
Contributions are welcome! If you'd like to contribute, please follow these steps:
- Fork the repository.
- Create a new branch for your feature or bug fix.
- Make your changes.
- Ensure all tests pass and pre-commit hooks run successfully.
- Write clear and concise commit messages.
- Open a pull request.
This project is licensed under the MIT License. See the LICENSE file for details.