Pythonista backend boilerplate. Alembic migrations, SQLAlchemy-native schema
Solar Stack — scaffold a customized copy with one command: see the ecosystem map
- Introduction
- Docker Hub image
- Setup
- Test the API
- Test the database
- How to add database migrations
- Integration and Unit Testing
- Linter
- Security Scan
Mars is the Pythonista variant of Mercury: same FastAPI stack, but schema is owned by Alembic and SQLAlchemy models instead of Flyway SQL files.
This project uses:
- Basic OAuth2 authentication, utilizing the FastAPI security module. It also supports user authentication via Google integration.
- PostgreSQL as its main database, Redis for caching, and Alembic for database migrations.
- Unit and integration tests.
- Security scanner (Bandit).
A pre-built API image is published on Docker Hub and updated on each push to main:
- Repository: ayoub3bidi/mars
docker pull ayoub3bidi/mars:latestUse it alongside your own Postgres and Redis setup, or clone this repo and run the full stack with docker compose (see Setup).
├── alembic
│ └── versions
├── src
│ └── assets
│ └── constants
│ └── controllers
│ ├── admin
│ ├── user
│ └── database
│ ├── postgres_db.py
│ ├── redis_db.py
│ └── integration_tests
│ └── middleware
│ ├── auth_guard.py
│ └── models
│ └── routes
│ ├── admin
│ ├── user
│ └── schemas
│ └── unit_tests
│ └── utils
│ └── app.py
│ └── main.py
│ └── restful_ressources.py
cp .env.dist .envThis will create a .env file in your project locally.
APP_TITLE="Mars API Docs"
APP_DESCRIPTION="This is the Swagger documentation of the Mars API"
APP_VERSION=0.1.0
API_URL="http://localhost:8000"
API_VERSION="v1"
APP_ENV=local
## Postgres Configuration
POSTGRES_HOST=mars_db
POSTGRES_PASSWORD=mars
POSTGRES_PORT=5432
POSTGRES_USER=mars
POSTGRES_DB=mars
POSTGRES_HOST_AUTH_METHOD=trust
POSTGRES_SIZE_POOL=30
POSTGRES_MAX_OVERFLOW=10
POSTGRES_POOL_TIMEOUT=30
POSTGRES_POOL_RECYCLE=1800
## Redis Configuration
REDIS_HOST=mars_cache
REDIS_PORT=6379
## JWT Configuration
JWT_SECRET_KEY="mysecretkey"
JWT_ALGORITHM="HS256"
ACCESS_TOKEN_EXPIRE_MINUTES=30
## OIDC Configuration
OIDC_GOOGLE_CLIENT_ID="changeme"
OIDC_GOOGLE_CLIENT_SECRET="changeme"
GOOGLE_AUTH_URL="https://accounts.google.com/o/oauth2/auth"
GOOGLE_TOKEN_URL="https://accounts.google.com/o/oauth2/token"
GOOGLE_USER_INFO_URL="https://www.googleapis.com/oauth2/v1/userinfo"docker compose up --build --force-recreateMigrations seed one admin user so you can try the API and admin routes right away:
| Password | |
|---|---|
| test@admin.com | Cloud.456 |
Get a JWT by calling POST /v1/token with form body username=test@admin.com and password=Cloud.456, then use the returned access_token as Authorization: Bearer <token> for admin endpoints. Change or remove this user in production.
You can check the Swagger documentation on localhost:8000.
curl localhost:8000/v1/healthThis will check the health of the API. The result should be like this:
{"alive":true, "status":"ok"}
docker exec -it mars_db psql -U marsThis command will take you inside the PostgreSQL database container where you can apply any SQL command you want.
psql (16.x)
Type "help" for help.
mars=# \d
List of relations
Schema | Name | Type | Owner
--------+------+-------+---------
public | user | table | mars
Schema changes flow from SQLAlchemy models through Alembic:
- Update or add models under
src/models/. - Autogenerate a revision against a running database:
docker compose up -d mars_db
alembic revision --autogenerate -m "describe_change"- Review the generated script in
alembic/versions/, then apply:
docker compose up --build --abort-on-container-exit mars_migrate
# or locally: alembic upgrade headTo roll back one revision:
alembic downgrade -1See the Alembic documentation for more.
One of important things that should be in every project is tests to keeps thing organized and make sure everything is working as intended.
Here's how to run the integration test locally:
docker compose up --build --abort-on-container-exit mars_integration_testsHere's how to run the unit tests locally:
docker compose up --build --abort-on-container-exit mars_unit_testsHaving a fast linter can help avoiding coding style problems, and potentially avoid future bugs that takes long hours to fix. For the linter we're working with ruff, a very fast linter written in Rust.
Here's how to run the linter test locally:
docker compose up --build --abort-on-container-exit mars_linterFor our project, we're using bandit, a tool designed to find common security issues in Python code. Here's how to run it locally:
docker compose up --build --abort-on-container-exit mars_securityInstall hooks locally to catch lint issues before CI:
pip install pre-commit
pre-commit install --install-hooks
pre-commit run --all-files- Model — add or update a SQLAlchemy model in
src/models/. - Alembic migration —
alembic revision --autogenerate -m "description", review, thenalembic upgrade head. - Schema — add Pydantic request/response schemas in
src/schemas/. - Controller — implement logic in
src/controllers/. - Route — wire the endpoint in
src/routes/and register it insrc/restful_ressources.py. - Tests — add coverage under
src/integration_tests/(andsrc/unit_tests/when appropriate).
Run ./ci/integration-test.sh after changes.
Contributions are welcome. See CONTRIBUTING.md, CODE_OF_CONDUCT.md, and SECURITY.md.
Give a star if this project helped you!
- Mercury — the original Flyway/SQL migration variant (unchanged).