Skip to content

Demo app

A working Todo CRUD app shipped with bluefox-core as a reference implementation.

Enabling it

app = create_bluefox_app(settings, demo=True)

This mounts a router at /demo/todos with full CRUD operations.

Note

The demo app requires a database. Make sure DATABASE_URL is set.

Endpoints

Method Path Description
GET /demo/todos List all todos
POST /demo/todos Create a todo
GET /demo/todos/{id} Get a todo by ID
PATCH /demo/todos/{id} Update a todo
PATCH /demo/todos/{id}/complete Mark a todo as completed
DELETE /demo/todos/{id} Delete a todo

Code structure

The demo follows the CQRS convention used across Bluefox apps:

bluefox_core/demo/
    __init__.py       # mount_demo(app)
    models.py         # DemoTodo SQLAlchemy model
    schemas.py        # Pydantic request/response schemas
    reads.py          # Pure read functions (list_todos, get_todo)
    writes.py         # Pure write functions (create, update, complete, delete)
    api.py            # FastAPI router wiring reads/writes to endpoints
    tests/
        conftest.py   # App and client fixtures with session override
        factories.py  # DemoTodoFactory for test data
        test_api.py   # Full CRUD test coverage

Reads and writes separation

Read functions only query — they never modify state:

async def list_todos(session: AsyncSession) -> list[DemoTodo]:
    result = await session.execute(select(DemoTodo))
    return list(result.scalars().all())

Write functions modify state but don't commit — the API layer handles commits:

async def create_todo(session: AsyncSession, data: TodoCreate) -> DemoTodo:
    todo = DemoTodo(**data.model_dump())
    session.add(todo)
    await session.flush()
    return todo

This pattern keeps business logic testable and gives the caller control over transaction boundaries.