Schema-driven FastAPI runtime: serve REST from SQLAlchemy models at startup

Posted by Prestigious-Bee2093@reddit | Python | View on Reddit | 6 comments

If you build APIs with SQLAlchemy and FastAPI, a large share of the work is repetitive: list/create/read/update/delete routes, relationship endpoints, Pydantic validation, filtering, and keeping OpenAPI in sync. That is roughly 90% of most backends.

The other 10% is what makes your product unique: custom business logic, integrations, auth flows, and one-off endpoints.

FastBackend is an open-source backend runtime (not a codegen tool). Your SQLAlchemy models are the source of truth. The CLI compiles them to a framework-agnostic IR, the FastAPI adapter serves REST + OpenAPI at startup, and you write Python only where it matters: app/custom/ for overrides and custom routes.

The Python-side problem

Typical FastAPI + SQLAlchemy flow:

  1. Define models in models.py
  2. Write CRUD routers for each entity
  3. Wire Pydantic schemas and validation
  4. Maintain OpenAPI manually or hope it stays accurate
  5. Schema changes → update routes, schemas, and docs again

FastBackend collapses steps 2-4. You keep your models. The runtime registers routes in memory from IR at startup.

How it works

SQLAlchemy models (models.py)
        ↓
   fastbackend generate
        ↓
.fastbackend/ir.json + openapi.yaml
        ↓
   fastbackend dev  (or uvicorn/Docker in prod)
        ↓
   FastAPI REST API + /docs

The IR is framework-agnostic. Same pipeline also has an Express adapter for Prisma/Node teams, but the Python path is SQLAlchemy or Prisma schema → fastbackend-fastapi runtime.

You still own:

Quick start (SQLAlchemy + FastAPI)

The CLI is on npm. The runtime is on PyPI.

npm install -g @fastbackend/cli

git clone https://github.com/darula-hpp/fastbackend.git
cd fastbackend/examples/sqlalchemy-fastapi

python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt

cp .env.example .env
fastbackend generate
fastbackend dev

Then open:

Try an override:

curl http://localhost:8301/users/1

Expected response (custom handler in app/custom/users_override.py):

{
  "id": 1,
  "name": "Override User",
  "email": "override@example.com",
  "source": "custom-override"
}

Custom code for the 10%

Generated routes cover CRUD and relationships. Overrides and custom routes cover business logic.

Custom route (new endpoint):

# app/custom/email.py
from fastapi import APIRouter

router = APIRouter()

@router.post("/users/{user_id}/send-email")
async def send_email(user_id: int):
    return {"status": "sent", "user_id": user_id}

Override (replace a generated route):

from fastapi import APIRouter
from fastbackend_fastapi import override

router = APIRouter()

@override("/users/{id}", "get")
@router.get("/users/{user_id}")
async def custom_get_user(user_id: int):
    return {"id": user_id, "name": "Override User", "source": "custom-override"}

The runtime discovers these at startup and merges them into the served API and OpenAPI output.

OpenAPI handoff

fastbackend generate writes .fastbackend/openapi.yaml. That spec is the contract for any frontend:

fastbackend generate
fastbackend dev   # API at http://localhost:8301

npx @uigen-dev/cli@latest init my-app --spec .fastbackend/openapi.yaml
npx @uigen-dev/cli@latest serve openapi.yaml --proxy-base http://localhost:8301

What's supported today

Adapter Stack Schema Persistence
FastAPI Python SQLAlchemy, Prisma In-memory (MVP)
Express TypeScript Prisma Prisma Client + Postgres

Published packages:

Command Purpose
fastbackend init Scaffold a new project
fastbackend generate Schema → IR + OpenAPI
fastbackend dev Local dev server (hot reload)
fastbackend build Production IR + OpenAPI (CI/deploy)
fastbackend test Run project tests (pytest in the FastAPI example)
fastbackend migrate DB migrations (adapter-specific)
fastbackend docker:build Build Docker image

Prod today: fastbackend build + run uvicorn/Docker (no fastbackend start yet).

Where this is going (not shipped yet)

Same philosophy for common backend services: declare the provider and URLs in config, keep secrets in .env, runtime wires the integration.

Planned:

Today is schema → IR → REST + OpenAPI. Service wiring is the direction, not the current release.

Honest limits

Links

Happy to answer questions about the IR pipeline, SQLAlchemy parsing, overrides, OpenAPI output, or how this compares to hand-rolled FastAPI routers.