Database API#

fastapi_restly.db.activate_savepoint_only_mode(make_session: async_sessionmaker[Any] | sessionmaker[Any]) None#

Intended for use in tests. Puts the session factory into savepoint-only mode so that no test data is ever committed to the database. Each test can roll back instantly by closing the session, leaving the database clean for the next test.

This is done with “create_savepoint” mode and a wrapper on engine.connect() that begins the outer transaction before the Session can use it. https://docs.sqlalchemy.org/en/20/orm/session_transaction.html#session-external-transaction

async fastapi_restly.db.async_create_all(base_or_metadata: type[DeclarativeBase] | MetaData) None#

Async equivalent of create_all(), on the configured async engine.

Usage:

await fr.db.async_create_all(Base)
fastapi_restly.db.configure(app: FastAPI | None = None, *, async_database_url: str | None = None, async_engine: AsyncEngine | None = None, async_make_session: async_sessionmaker[Any] | None = None, database_url: str | None = None, engine: Engine | None = None, make_session: sessionmaker[Any] | None = None, session_generator: Callable[[], AsyncIterator[AsyncSession]] | None = None, sync_session_generator: Callable[[], Iterator[Session]] | None = None, warn_on_misuse: bool | None = None, warn_on_uncommitted: bool | None = None, install_default_exception_handlers: bool = True) None#

Configure FastAPI-Restly. Call once at startup.

Pass async parameters (async_database_url, async_engine, or async_make_session) to enable async support, sync parameters (database_url, engine, or make_session) for sync support, or both if your application uses both.

Use session_generator / sync_session_generator (or engine / make_session) to construct sessions your way – a custom engine, isolation level, search_path, logging, an existing sessionmaker. A custom generator’s job is to construct, yield, and clean up (close / roll back on the way out); it must not commit. Customizing how a session is built never takes the commit away from Restly.

Restly owns the commit. Every write – the CRUD handlers (handle_create / handle_update / handle_delete) and write_action – runs before_commit -> commit -> after_commit around your domain logic; the commit is the framework’s single responsibility. A custom (non-CRUD) write route either brackets its mutation with write_action(...) (recommended) or commits the session itself with await self.session.commit().

By default Restly warns (RestlyUncommittedChangesWarning) when a request finishes with uncommitted changes still in the session – the tell of a custom write route that forgot to commit. This applies to every session source, built-in or custom. A route that intentionally leaves a flush uncommitted (a validate-then-rollback dry run) should suppress the warning for just that request with session.info["_fr_suppress_uncommitted"] = True. warn_on_uncommitted=False turns the check off globally; that is rarely the right response to the warning – prefer fixing the missing commit or the per-route suppression.

Pass warn_on_misuse=True to enable opt-in registration-time misuse warnings (RestlyMisuseWarning): when a view class is registered via include_view, the framework flags route-shell overrides, direct session.commit() calls in view methods, and CRUD route sets hand-rolled on a bare View. Off by default; intended for development, templates, and CI. Enable it before registering views.

Pass your FastAPI app to install fastapi-restly’s default exception handlers (currently: a translator that turns SQLAlchemy IntegrityError into HTTP 409 Conflict). Set install_default_exception_handlers=False to opt out. If you do not pass app here, the handlers are registered the first time a view is mounted via fastapi_restly.include_view() instead.

fastapi_restly.db.create_all(base_or_metadata: type[DeclarativeBase] | MetaData) None#

Create all tables for base_or_metadata on the configured sync engine.

A dev/demo convenience over metadata.create_all(engine) so a quickstart can create its schema without reaching for the raw engine:

fr.db.create_all(Base)  # or fr.db.create_all(Base.metadata)

Accepts a DeclarativeBase subclass (its .metadata is used) or a MetaData. Requires configure() first. Use Alembic migrations in production.

fastapi_restly.db.deactivate_savepoint_only_mode(make_session: async_sessionmaker[Any] | sessionmaker[Any]) None#

Reverts the effect of activate_savepoint_only_mode. Restores the original engine.connect and disables savepoint-only mode.

fastapi_restly.db.get_async_engine() AsyncEngine#

Return the async engine registered via configure().

fastapi_restly.db.get_engine() Engine#

Return the sync engine registered via configure().

fastapi_restly.db.open_async_session() AsyncGenerator[AsyncSession]#

Open an async database session for use outside of request context.

Resolves the same source as AsyncSessionDep: a custom session_generator passed to fastapi_restly.configure() if one is configured, otherwise the built-in async session factory. (The request-only uncommitted-changes check is not armed here – off-HTTP code owns its commit, exactly as a custom write route does.)

Example:

async with fr.open_async_session() as session:
    result = await session.execute(select(User))
fastapi_restly.db.open_session() Generator[Session]#

Open a sync database session for use outside of request context.

Resolves the same source as SessionDep: a custom sync_session_generator passed to fastapi_restly.configure() if one is configured, otherwise the built-in sync session factory. (The request-only uncommitted-changes check is not armed here – off-HTTP code owns its commit, exactly as a custom write route does.)

Example:

with fr.open_session() as session:
    result = session.execute(select(User))

See also

Use Restly in an Existing Project — wiring Restly into existing engines and sessions; Deploying — production engine configuration.