HOSTING FOR AI-BUILT APPS
Deploy a FastAPI polling API with PostgreSQL on Yeeted
A Yeeted sample: polls and voting. What it demonstrates:
- FastAPI + SQLAlchemy + alembic: the platform detects
alembic.iniand runsalembic upgrade headat release against the injectedDATABASE_URL, so the schema (two revisions here) is migrated before the app serves. - Correctness lives in the database: one vote per voter per poll is a unique constraint, not an app-side check two racing requests both pass.
- Zero-service local run: without
DATABASE_URLit uses sqlite, which is also what the unit tests migrate and run against.
Tests: pytest tests/test_polls.py (unit) ·
POLL_URL=https://... pytest tests/test_integration.py ·
./smoke.sh https://....
Run locally
Use Python 3.10 or newer. From python/poll-fastapi inside the examples tree:
python3 -m venv .venv
. .venv/bin/activate
pip install -r requirements.txt
pip install pytest httpx
alembic upgrade head
uvicorn app.main:app --host 0.0.0.0 --port 8000
With no DATABASE_URL, Alembic and the app use polls.db in this directory.
Open http://localhost:8000/docs for the interactive API. Run
pytest tests/test_polls.py in the same environment to test migrations,
validation, successful voting, and duplicate-vote rejection against SQLite.
Deploy and verify
Follow the deployment walkthrough. Deploy this
folder with its yeeted.yaml, alembic.ini, and alembic/ revisions. The
manifest requests PostgreSQL; Yeeted supplies DATABASE_URL and runs the
Alembic release migration before serving the API on port 8000.
sh smoke.sh "$PREVIEW_URL"
POLL_URL="$PREVIEW_URL" pytest tests/test_integration.py
The smoke script checks health, creates a poll, and reads its initial total of
zero. To verify voting, create a poll with POST /api/polls and JSON
{"question":"What should we build?","options":["Blog","Notes"]}. Read
GET /api/polls/{id} and use an option ID from that response in
POST /api/polls/{id}/vote with {"option_id":1,"voter":"demo-reader"},
replacing 1 with the actual option ID. The first vote should return 200;
repeating that voter on the same poll should return 409.
What to change before real use
The voter is a caller-supplied string, not an authenticated identity. The unique constraint rejects duplicate voter strings, but does not prevent a person using multiple strings. Vote totals use a read-modify-write increment, so concurrent distinct voters can lose increments. Do not use this example as an election system or a correctness benchmark under load. Add identity and atomic counter updates before adapting it for concurrent voting.