A small todo API, live on its own URL in minutes, with every endpoint testable from the
browser at /docs. FastAPI, SQLAlchemy 2 and Pydantic on the front, managed Postgres behind.
The todos are the least interesting part. The point of this template is the wiring: how an API finds its database, creates its tables, rides out a database that is not there yet, and reports health honestly. Swap the todos for your own resources and keep the rest.
- Finding the database. The managed Postgres bound to the app arrives as
DATABASE_URL.db.pyrewrites itspostgres://scheme topostgresql+psycopg://, which SQLAlchemy needs, and leavessslmode=requireto libpq, which encrypts without checking the certificate against public CAs: exactly what velixir's own CA calls for. - Tables on start, without the crash loop. A background thread creates the tables and
keeps retrying until the database answers. Meanwhile the API returns 503 with a
Retry-Afterheader and the home page explains the wait. It recovers on its own. - A setup page instead of a crash. Start it with no database and
/says exactly how to bind one, the API answers 503 with the same instructions, and/healthzstays green. - An honest health check.
/healthzrunsSELECT 1, so a lost database takes the app out of rotation rather than letting it serve errors. - Types as the contract. Pydantic models decide what the API accepts and returns, and the
docs at
/docsand the schema at/openapi.jsonare generated from the same code. - Correct behind the proxy. uvicorn trusts the edge's forwarded headers
(
--forwarded-allow-ips "*"in theProcfile), so the app sees the visitor's address and scheme rather than the edge's.
Deploy it from the gallery. velixir creates a managed Postgres, binds it to the app as
DATABASE_URL, and holds the first deploy until the database is running, so the app starts
connected. The table is created on first boot.
By hand, for example after deploying your own copy with velixir deploy:
- Create a managed Postgres from the Databases page, or run
velixir db create. - Bind it to the app as
DATABASE_URL: on the database's page under Bound apps, orvelixir db bind <database-id> --app <app-id>. - Redeploy, with the Redeploy button on the live release in the Deploys tab.
| Method | Path | Does |
|---|---|---|
GET |
/ |
A landing page with links to the docs |
GET |
/docs |
Interactive docs: try every endpoint from the browser |
GET |
/redoc |
The same API as a reference page |
GET |
/api/todos |
Newest 100 todos as JSON, ?done=true or ?done=false to filter |
POST |
/api/todos |
Create one, {"title": "..."} |
GET |
/api/todos/{id} |
One todo |
PATCH |
/api/todos/{id} |
Change title, done, or both |
DELETE |
/api/todos/{id} |
Delete one |
GET |
/healthz |
200 when the database answers (or no database is bound yet), 503 while it is unreachable |
python -m venv .venv
. .venv/bin/activate # .venv\Scripts\activate on Windows
pip install -r requirements.txt
DATABASE_URL=postgres://user:pass@localhost:5432/todos uvicorn main:app --reload --port 8080Then open http://localhost:8080/docs. With no sslmode in the URL, the connection is plain
TCP, which is what a local Postgres expects.
velixir deployThere is no authentication. Anyone with the URL can read, change and delete every todo. Add auth before storing anything you care about. FastAPI's security helpers make an API key header a few lines of code.
Tables are created, not migrated. create_all makes missing tables and never alters
existing ones, so a column added to the model does not reach a table that already exists.
Move to a migration tool such as Alembic before your first schema change on real data.
One process by default. It already serves many requests at once: uvicorn is asynchronous,
and the database handlers run in a thread pool. On a bigger plan, set WEB_CONCURRENCY for
more worker processes.
The certificate is not verified by default. The connection is encrypted, but sslmode=require does
not check who issued the certificate, which matches what it means everywhere else. To verify the
server as well, download your database's CA certificate from its page in the velixir dashboard
and connect with sslmode=verify-full. See
https://velixir.net/docs/databases#verifying-the-server-certificate.
The Free plan sleeps. After 15 idle minutes the app stops, and the next request wakes it, which takes a few seconds.
MIT.