API-first URL shortener built on the MLH PE stack. Team submission for Reliability Engineering: tests in CI, health checks, structured JSON errors, Docker restart policy, and documented failure modes.
Stack: Flask · Peewee ORM · PostgreSQL · uv · Gunicorn · Docker · GitHub Actions
- pytest integration tests under
tests/hitting the HTTP API - GitHub Actions runs tests + Postgres on every push/PR to
main GET /health— always JSON; includes DB check (ok/degraded)- pytest-cov on
appwith--cov-fail-under=70in CI - Graceful errors — 4xx/5xx return JSON (see
app/errors.py) - Docker Compose —
restart: alwaysonappanddbfor chaos-style demos - Failure modes — FAILURE_MODES.md
- API manual tests — TESTING.md
git clone https://github.com/yubelgg/url_shortener.git && cd url_shortener
uv sync
createdb hackathon_db # or your Postgres admin tool
cp .env.example .env # match your DB user/password/name
uv run python seed.py # optional: load CSV seed data
uv run run.pyDev server uses port 5001:
curl -s http://localhost:5001/healthcp .env.example .env # DATABASE_* must match between db and app
docker compose up --buildApp on http://localhost:5001 (host) → container 8080. Postgres is reachable inside Compose as host db.
The app is wired for continuous deployment: new commits pushed to the connected branch (typically main) trigger an automatic redeploy on DigitalOcean App Platform.
Quick checks (use https):
curl -sS "https://urlshortener-rp6zs.ondigitalocean.app/health"Keep local URLs (localhost:5001, Docker Compose) for development; use the deployed URL above for demos and judges hitting production.
uv sync --group dev
uv run pytest tests/ -v
uv run pytest tests/ --cov=app --cov-report=term-missing --cov-fail-under=70| Area | Routes |
|---|---|
| Health | GET /health |
| Users | GET/POST /users, GET/PUT /users/:id, POST /users/bulk |
| URLs | GET/POST /urls, GET/PUT /urls/:id (inactive URLs hidden from public GET) |
| Redirect | GET /r/:short_code → 302 + clicked event |
| Events | GET /events |
| Seed (ops) | GET /seed — loads CSVs (protect/remove in real production) |
Full curl examples: TESTING.md.
Use the seed CSVs and platform guidance from MLH PE Hackathon for judging and schema expectations.
app/
__init__.py # app factory, /health, /seed
database.py # Peewee + connection lifecycle
errors.py # JSON error handlers
health.py # health check logic
models/ # User, Url, Event
routes/ # users, urls, events, redirect
tests/ # pytest API + error coverage
.github/workflows/ # CI
Generated from the MLH PE Hackathon template; extended for reliability and URL-shortener behavior.