Simple, production-ready FastAPI service with async PostgreSQL (SQLAlchemy 2 + asyncpg), Redis cache-aside, and structured JSON logging with per-request correlation IDs.
- Click the button above (or deploy this repo into a new Railway project).
- Add the PostgreSQL and Redis plugins — Railway injects
DATABASE_URLandREDIS_URLautomatically; no extra config needed. - The app reads
$PORTand those URLs on boot. Health check path is/ready(seerailway.json), so deploys wait until Postgres and Redis are reachable.
- Async stack: FastAPI + SQLAlchemy 2.0 async + asyncpg.
- Redis cache-aside on item reads; a Redis outage degrades gracefully (falls back to DB).
- JSON logging to stdout with
request_id, method, path, status, and duration. - Health probes:
/health(liveness) and/ready(checks Postgres + Redis). - Railway-friendly: reads
DATABASE_URL/REDIS_URL, binds to$PORT, normalizespostgres://URLs.
| Method | Path | Description |
|---|---|---|
| GET | /health |
Liveness (process up) |
| GET | /ready |
Readiness (Postgres + Redis up) |
| POST | /items |
Create item |
| GET | /items |
List items (limit, offset) |
| GET | /items/{id} |
Get item (cached) |
| DELETE | /items/{id} |
Delete item (invalidates cache) |
Interactive docs at /docs.
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
cp .env.example .env # adjust DATABASE_URL / REDIS_URL
uvicorn app.main:app --reloadRequires a reachable PostgreSQL and Redis (set their URLs in .env).
curl -X POST localhost:8000/items -H 'content-type: application/json' \
-d '{"name":"hello","description":"world"}'
curl localhost:8000/items/1 # second call is served from Redis
curl localhost:8000/readypip install -r requirements.txt -r requirements-dev.txt
pytestTests use in-memory SQLite and a fake Redis, so no live Postgres/Redis is needed.
init_db()runscreate_allon startup for convenience. For real schema changes, use Alembic migrations instead of relying on auto-create.- Logs are single-line JSON on stdout; pass structured fields via
logger.info("msg", extra={...}).