A FastAPI template that integrates Poetry, Alembic, SQLAlchemy, dotenv (Pydantic), Docker, and PostgreSQL for a fully functional API setup.
Docker is set up to run both a FastAPI and PostgreSQL container.
Alembic files are included as references to help you understand how to modify them. However, as noted in the "Setup" section, you should remove and reinitialize these files before starting your own API project.
This project strucure is based on project-structure-consistent--predictable by zhanymkanov. It has been modified to use poetry and docker instead of venv.
fastapi-template
├── alembic/
├── src
│ ├── auth # package
│ │ ├── config.py # local configs
│ │ ├── dependencies.py # specific auth router dependencies
│ │ ├── exceptions.py # package-specific errors
│ │ ├── models.py # database models
│ │ ├── router.py # auth router with endpoints
│ │ ├── schemas.py # pydantic models
│ │ ├── service.py # package-specific business logic
│ │ └── utils.py # any other non-business logic functions
│ ├── aws
│ │ ├── client.py # client model for external service communication
│ │ ├── config.py
│ │ ├── exceptions.py
│ │ ├── schemas.py
│ │ └── utils.py
│ └── package # copy paste package
│ │ ├── config.py
│ │ ├── dependencies.py
│ │ ├── exceptions.py
│ │ ├── models.py
│ │ ├── router.py
│ │ ├── schemas.py
│ │ ├── service.py
│ │ └── utils.py
│ ├── __init__.py
│ ├── config.py # global configs (dotenv, etc)
│ ├── models.py # global database models
│ ├── exceptions.py # global exceptions
│ ├── pagination.py # global module e.g. pagination
│ ├── database.py # database connection related stuff
│ └── main.py
├── tests/
│ ├── auth
│ ├── aws
│ └── posts
├── .env.example # Variables used/needed in this .env
├── .gitignore
├── alembic.ini
├── compose.yaml
├── Dockerfile
├── LICENSE
├── poetry.lock
├── pyproject.toml
└── README.md
-
Store all domain directories inside
src
foldersrc/
- highest level of an app, contains common models, configs, and constants, etc.src/main.py
- root of the project, which inits the FastAPI app
-
Each package has its own router, schemas, models, etc.
config.py
- e.g. specific env varsdependencies.py
- router dependenciesexceptions.py
- module specific exceptions, e.g.PostNotFound
,InvalidUserData
models.py
- for database modelsrouter.py
- is a core of each module with all the endpointsschemas.py
- for pydantic modelsservice.py
- module specific business logicutils.py
- non-business logic functions, e.g. response normalization, data enrichment, etc.
-
When package requires services or dependencies or configs from other packages - import them with an explicit module name
from src.auth import config as auth_config
from src.notifications import service as notification_service
from src.posts.config import ErrorCode as PostsErrorCode # in case we have Standard ErrorCode in config module of each package
Ensure that Poetry is installed. If you plan to use Docker and don't require IDE support for package management, you can skip this step.
-
Update project dependencies, this will also create a virtualenv and install them. (100% they are outdated):
poetry update
-
To add or update a package:
poetry add <package-name>
or for development dependencies:
poetry add --group=dev <package-name>
Environment variables are handled via a .env
file. The .env.example
file contains the essential variables required to run this project out of the box.
-
Create a
.env
file at the project root:touch .env
-
Add your environment-specific variables:
DB_URL=postgresql://postgres:1234@fastapi-postgres:5432/postgres ALEMBIC_DB_URL=postgresql://postgres:1234@localhost:5432/postgresn
The .env
file is used by the pydantic-settings
package to load environment variables into the FastAPI application. To locate the PostgreSQL container's IP address, inspect the Docker network that is created.
-
Make sure Docker is installed on your system.
-
Build and run the Docker containers:
docker compose up -d
This will start both the FastAPI app and the PostgreSQL database as Docker containers.
-
To stop the containers (add --volumes to remove persistent PostgeSQL data):
docker-compose down
-
Checking logs:
docker compose logs --follow -t
-
Remove alembic example:
rm -rf alembic/ alembic.ini
-
Initialize Alembic (creates the alembic dir and alembic.ini):
poetry run alembic init alembic
-
Configure the
alembic/env.py
file to use yourALEMBIC_DB_URL
from.env
:# Set up ALEMBIC_DB_URL from .env file import os from dotenv import load_dotenv load_dotenv() ALEMBIC_DB_URL = os.getenv("ALEMBIC_DB_URL") # Set up sqlalchemy.url (alembic.ini) variable config.set_main_option("sqlalchemy.url", ALEMBIC_DB_URL) # Import ALL the models from the app (even if unused) from src.database import Base from src.package.models import Todos # ... # Set target_metadata target_metadata = Base.metadata
-
Create a new migration script (you can remove --autogenerate and create the change yourself):
# DATABASE HAS TO BE RUNNING! poetry run alembic revision --autogenerate -m "description of changes"
-
Apply the migrations:
poetry run alembic upgrade {REVISION_ID}