patrickbeane ddf5e983e2 Initial commit: Quote of the Day API
Secure, rate‑limited Flask + Gunicorn microservice with SQLite persistence, delivery tracking, and systemd deployment config. Includes setup script, HTML template, and production‑ready README.
2025-08-30 13:24:33 -04:00
2025-08-30 13:24:33 -04:00
2025-08-30 13:24:33 -04:00

Quote of the Day API

A secure, ratelimited microservice serving curated jokes and quotes from a persistent SQLite database. Built for fun, engineered for production.


📖 Overview

Quote of the Day is a small but production-minded API designed to demonstrate:

  • Rate limiting flask-limiter enforces perIP request caps to prevent abuse.
  • Persistent storage SQLite replaces JSON to ensure atomic reads/writes and avoid race conditions under concurrent access.
  • Proxy awareness ProxyFix middleware ensures correct client IP logging behind reverse proxies.
  • Organic usage The live API has been discovered and now serves hundreds of requests daily.

Features

  • Randomized quote delivery with delivery count tracking
  • Plain text and JSON endpoints
  • Rate-limited access to prevent abuse
  • Systemd-ready deployment with Gunicorn
  • SQLite-backed persistence for safe concurrent access

🗂 Architecture

[ Client ]
   |
   v
[ Flask + Gunicorn ]
   |
   v
[ SQLite DB (quotes.db) ]

🚀 Endpoints

Method Path Description Rate Limit
GET / HTML frontend (quotes.html) N/A
GET /quote Returns a random quote as plain text 20/minute
GET /api/quote Returns a random quote as JSON 50/minute

📦 Running Locally

# Clone the repo
git clone https://github.com/patrickbeane/quote-of-the-day.git
cd quote-of-the-day

# (Optional) Create a virtual environment
python3 -m venv venv && source venv/bin/activate

# Install dependencies
pip install -r requirements.txt

# Edit `add-quotes.py` with your favorite quotes
nano add-quotes.py

# Run `add-quotes.py` to generate the DB
python add-quotes.py

# Run the API
python quotes.py

Visit http://<your-server-ip>:5051 for the HTML frontend or http://<your-server-ip>:5051/api/quote for JSON output.


📝 Example Output

{
  "id": 1,
  "quote": "Strive not to be a success, but rather to be of value.",
  "author": "Albert Einstein",
  "delivered": 3
}

🛠 Deployment with systemd

For production use, this service can be run behind Gunicorn and managed via systemd.

A sample unit file is included in deploy/quotes.service:

sudo cp deploy/quotes.service /etc/systemd/system/
sudo systemctl daemon-reexec
sudo systemctl enable quotes
sudo systemctl start quotes

🔒 Production Considerations

  • Rate limiting prevents abuse and keeps the service responsive.
  • SQLite ensures atomic writes and safe concurrent access.
  • ProxyFix ensures accurate IP logging behind reverse proxies.

🏗 Production Deployment (on my infra)

[ Client ]
   |
   v
[ Hermes (Docker + Caddy) ]
   |
   v
[ Hades (Flask + Gunicorn) ]
   |
   v
[ SQLite DB (quotes.db) ]

📊 Fun Fact

The live API has been hit by automated clients and bots, resulting in some quotes being "delivered" hundreds of times - a realworld example of why rate limiting and logging matter.


📜 License

MIT License free to use, modify, and share.

Description
Secure, rate‑limited Flask + Gunicorn microservice with SQLite persistence, delivery tracking, and systemd deployment config. Includes setup script, HTML template, and production‑ready README.
Readme 51 KiB
Languages
Python 91.3%
HTML 8.7%