FastAPI + CUBRID API Service Template¶
Overview¶
Production-ready starter template for building REST APIs with FastAPI, SQLAlchemy 2.0, and CUBRID 11.2. It is intentionally lean: sync SQLAlchemy session lifecycle, clean repository pattern, and Docker-first local setup.
Quick Start¶
- Copy this template and move into the directory.
- Create your environment file:
- Start services:
- Open:
- API:
http://localhost:8000 - Swagger UI:
http://localhost:8000/docs - Health:
http://localhost:8000/health
What is published, and resetting the data¶
Compose publishes the CUBRID broker (127.0.0.1:33000) and the API
(127.0.0.1:8000) on this host only. The lab dba account has no password, so
the broker is never published on other interfaces. To let other machines reach
the API on purpose, set API_HOST_IP (for example
API_HOST_IP=0.0.0.0 docker compose up --build, or a line in .env).
The database lives in the named volumes cubrid_data and cubrid_databases.
docker compose down keeps it; docker compose down -v deletes it, which resets
the template to an empty database.
Upgrading a stack started from an earlier compose file¶
CUBRID records the host name of the container that created the database. Earlier
files gave the cubrid service no fixed host name (before #413) or the host name
cubrid-api-service, and named the containers cubrid-db and fastapi-service.
The current file sets CUBRID_DB_HOST: localhost and leaves the container names
to Compose. It recreates the container but keeps the database in its volume, so
the health check fails with -353 Failed to connect to database server and the
API does not start. Point the database at localhost once, from this folder:
docker compose up -d cubrid
docker compose exec -T -u cubrid cubrid sh -c 'sed -i -E "s/^(testdb[[:space:]]+[^[:space:]]+[[:space:]]+)[^[:space:]]+/\1localhost/" "$CUBRID_DATABASES/databases.txt"'
docker compose restart cubrid
docker compose up -d
If the data is disposable, run docker compose down -v and then
docker compose up --build instead, to start with a fresh database.
Project Structure¶
app/
├── main.py # FastAPI app factory, lifespan, CORS
├── config.py # pydantic-settings based configuration
├── database.py # SQLAlchemy engine/session/base
├── models.py # cookbook_items, cookbook_categories
├── schemas.py # Request/response models
├── crud.py # Repository pattern CRUD logic
└── routes/
├── health.py # GET /health
└── items.py # Item CRUD endpoints
API Endpoints¶
GET /health→{"status": "ok", "database": "connected"}GET /items?skip=0&limit=20→ paginated item listGET /items/{item_id}→ single itemPOST /items→ create itemPUT /items/{item_id}→ update itemDELETE /items/{item_id}→ delete item
Configuration¶
Environment variables (see .env.example):
DATABASE_URL(defaultcubrid+pycubrid://dba@cubrid:33000/testdb)APP_HOST(default0.0.0.0)APP_PORT(default8000)
Additional settings in app/config.py:
APP_NAMEDEBUGCORS_ORIGINS
Development¶
- Tables are auto-created at startup via
Base.metadata.create_all(). - SQLAlchemy access is fully parameterized through ORM/query builder usage.
- Keep this template starter-focused: no auth, no migrations, no framework over-abstraction.
- Run locally without Docker:
- Do not add
index=Trueto primary key columns: CUBRID rejects a second index on columns a primary key orUNIQUEconstraint already indexes, socreate_all()fails at startup. - Each recipe under
recipes/ships a test suite that runs against live CUBRID whenCUBRID_TEST_URLis set and falls back to in-memory SQLite otherwise. See the Test section of each recipe's README.