A powerful, scalable template to kickstart your backend projects. Includes FastAPI with Docker integration, JWT authentication, optional Logfire instrumentation, and PEP-582-based dependency management via Astral's uv.
Inspired by Radoslav Georgiev's Django Structure for Scale lecture and my own experience, this template offers a structured approach to building scalable web applications.
- β¨ Features
- π Project Structure
- π‘ Getting Started
- π οΈ Using auto-module.py
- π§ Environment Variables
- π JWT Auth & Security
- π License
- π Deploy
- π€ Contribute to the Project
- π¬ Contact
- FastAPI template with JWT authentication and Alembic migrations.
- Docker & docker-compose configs for zero-friction container development.
- Astral
uvfor dependency installation and script execution (no manualvenvactivation). - Logfire auto-instrumentation: set
LOGFIRE_TOKENin your environment and the app will automatically send logs to Pydantic Logfire. - Modular structure inspired by scaling best practices.
- Optional
uvloopintegration for improved asyncio performance (Linux/macOS only).
.vscode/
alembic/
app/
author/
routes/
__init__.py
base.py
schemas/
__init__.py
base.py
create.py
edit.py
response.py
annotations.py
apis.py
crud.py
exceptions.py
formatters.py
models.py
selectors.py
services.py
common/
annotations.py
auth.py
cache.py
crud.py
dependencies.py
exceptions.py
paginators.py
schemas.py
security.py
types.py
utils.py
core/
database.py
handlers.py
settings.py
tags.py
external/
main.py
tests/
.env_sample
.flake8
.gitignore
.pylintrc
.python-version
alembic.ini
auto-module.py
docker-compose.yml
Dockerfile
LICENSE
pyproject.toml
pytest.ini
railway.toml
README.md
requirements.txt
start.sh
uv.lock
- Docker & Docker Compose (optional)
uvinstalled globally
git clone https://github.com/GrandGaleTechnologies/behemoth-fastapi
cd behemoth-fastapi# Optional: add uvloop (doesnt work well on windows)
uv add uvloop
uv venvCreate a .env file and add environment variables (use Environment Variables as a guide).
# With uv
uv run alembic upgrade headuv run fastapi devuv run fastapi runThis script automates creation of new FastAPI modules with a consistent folder layout:
app/
βββ ModuleName/
βββ routes/__init__.py
βββ routes/base.py
βββ schemas/base.py
βββ schemas/create.py
βββ schemas/edit.py
βββ schemas/response.py
βββ apis.py
βββ models.py
βββ services.py
βββ selectors.py
βββ exceptions.py
βββ formatters.pyuv run auto-module.pyFollow the prompts to specify the module name.
See configuration and instructions in docs/ENV.md. Use .env_sample as your template.
- Implemented in
common/auth.pyandcommon/security.py - Leverages FastAPI's
Dependsand reusableget_current_user()function - Tokens include expiration and are signed using a secret key in
.env
To protect a route:
from common.dependencies import get_current_user
@app.get("/secure-data")
def secure_data(user: User = Depends(get_current_user)):
return {"message": f"Hello, {user.username}!"}- User logs in via
/loginendpoint β receives JWT access token - Frontend stores token (e.g., in localStorage or Authorization header)
- Token is sent with each protected request
- Backend validates token and grants access
This project uses Redis-based rate limiting through fastapi-limiter. By default, it allows 3 requests per second per endpoint.
You can run Redis directly as a standalone container:
docker run -d \
--name behemoth-redis \
-p 6379:6379 \
-v redis_data:/data \
redis:latestThis will:
- Run Redis in detached mode (
-d) - Name the container
behemoth-redis - Expose Redis on port
6379 - Persist data in a Docker-managed volume (
redis_data)
docker exec -it behemoth-redis redis-cli pingYou should see PONG as the response.
Update your .env file with the Redis container URL (since itβs exposed on localhost):
REDIS_BROKER_URL=redis://localhost:6379/0-
Swagger UI
- Navigate to
http://localhost:8000 - Make multiple rapid requests to any endpoint
- After 3 requests within 1 second, youβll receive a 429 Too Many Requests
- Navigate to
-
Curl
for i in {1..4}; do curl http://localhost:8000/health; donedocker exec -it behemoth-redis redis-cli monitorIf Redis connection fails:
- Check container status:
docker ps -f name=behemoth-redis- View logs:
docker logs behemoth-redis- Restart Redis:
docker restart behemoth-redisUpdate your .env file with the Redis container URL:
REDIS_BROKER_URL=redis://redis:6379/0Rate limiting is configured in app/main.py:
REQ_RATE = 3 # Number of requests allowed
REQ_RATE_TIME = 1 # Time window in secondsThis means each endpoint allows 3 requests per second. After exceeding this limit, requests will receive a 429 (Too Many Requests) response.
-
Swagger UI:
- Navigate to
http://localhost:8000 - Make multiple rapid requests to any endpoint
- After 3 requests within 1 second, you'll receive a 429 response
- Navigate to
-
Using Docker CLI:
# Make multiple requests quickly
for ($i = 1; $i -le 4; $i++) {
docker-compose exec api curl http://localhost:8000/health
}Monitor Redis rate limiting in real-time:
docker-compose exec redis redis-cli monitor```python
from app.common.cache import CacheManager
from app.sample_module.schemas import SampleModel # Example Pydantic model
# Initialize for a specific model with a TTL of 300 seconds
sample_cache_manager = CacheManager(ttl=300, model_class=SampleModel)
# Or initialize without a model_class if you just need to store/retrieve raw data
generic_cache_manager = CacheManager(ttl=60)
```
-
Set Data in Cache:
# For sample_cache_manager (with SampleModel) await sample_cache_manager.set( data={"id": 1}, value=SampleModel(id=1, name="Test"), cache_prefix="sample:" ) # For generic_cache_manager (raw dict) await generic_cache_manager.set( data={"key": "my_data"}, value={"message": "Hello, cached world!"}, cache_prefix="generic:" )
-
Get Data from Cache:
# For sample_cache_manager (will return SampleModel instance or None) cached_sample = await sample_cache_manager.get(data={"id": 1}, cache_prefix="sample:") if cached_sample: print(f"Cached Sample: {cached_sample.name}") # For generic_cache_manager (will return dict or None) cached_generic = await generic_cache_manager.get( data={"key": "my_data"}, cache_prefix="generic:" ) if cached_generic: print(f"Cached Generic: {cached_generic['message']}")
If Redis connection fails:
- Check Redis container status:
docker-compose ps redis- View Redis logs:
docker-compose logs redis- Verify Redis network connectivity:
docker-compose exec api ping redis- Check Redis container health:
docker inspect -f '{{.State.Health.Status}}' behemoth-fastapi-redis-1- Restart Redis
This project uses pre-commit hooks to ensure code quality. The hooks include Ruff for linting and formatting, and Flake8 for additional code style checks.
- Install pre-commit:
uv add --dev pre-commit- Install the pre-commit hooks:
pre-commit install- The hooks will run automatically on
git commit - To manually run the hooks on all files:
pre-commit run --all-files- To run specific hooks:
pre-commit run ruff --all-files
pre-commit run flake8 --all-filesPre-commit configuration is stored in .pre-commit-config.yaml and includes:
- Ruff for linting and formatting
- Flake8 for additional code style checks
This project is licensed under the MIT License - see the LICENSE file for details.
Deploy this template on Railway:
Contributions are welcome! Fork the repo, create a branch, and submit a PR. Engage in discussions for ideas and improvements.
- Name: GrandGale Technologies
- Email: [email protected]
- GitHub: https://github.com/GrandGaleTechnologies
- LinkedIn: https://linkedin.com/in/angobello0
- Upwork: https://www.upwork.com/freelancers/~01bb1007bf8311388a
- Instagram: https://www.instagram.com/bello_ango0/