How-To: Use FastAPI-Restly in an Existing Project#
Provide Your Own Session Generator#
If your project already manages its own database sessions, configure FastAPI-Restly to use them instead of its built-in session factory.
For async views (AsyncRestView), pass an async generator to
fr.configure():
from typing import AsyncIterator
from sqlalchemy.ext.asyncio import AsyncSession
import fastapi_restly as fr
async def my_get_db() -> AsyncIterator[AsyncSession]:
...
yield MyAsyncSession()
fr.configure(session_generator=my_get_db)
For sync views (RestView), pass a sync generator:
from typing import Iterator
from sqlalchemy.orm import Session
import fastapi_restly as fr
def my_get_db() -> Iterator[Session]:
...
yield MySession()
fr.configure(sync_session_generator=my_get_db)
You can also use FastAPI-Restly’s configured session proxy directly in your own code (for example in background tasks):
import fastapi_restly as fr
async with fr.async_session() as session:
result = await session.execute(...)
Use Your Own DeclarativeBase Models#
If your project already has SQLAlchemy models on a custom DeclarativeBase,
you can use those models directly in FastAPI-Restly views:
import fastapi_restly as fr
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
class AppBase(DeclarativeBase):
pass
class World(AppBase):
__tablename__ = "world"
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
message: Mapped[str]
@fr.include_view(app)
class WorldView(fr.AsyncRestView):
prefix = "/world"
model = World
FastAPI-Restly supports these models for generated CRUD routes and
auto-generated schemas. When creating tables, use your own base metadata
(for example AppBase.metadata.create_all(...)).
Isolating Runtime State Per App#
FastAPI-Restly keeps default runtime state (session factories, database URLs)
in a module-level FRGlobals instance. When running multiple apps in the same
process you can isolate state per context:
from fastapi_restly.db import FRGlobals, use_fr_globals
app_a_globals = FRGlobals()
app_b_globals = FRGlobals()
with use_fr_globals(app_a_globals):
fr.configure(async_database_url="postgresql+asyncpg://host-a/db")
...
with use_fr_globals(app_b_globals):
fr.configure(async_database_url="postgresql+asyncpg://host-b/db")
...
use_fr_globals uses a ContextVar internally, so concurrent async tasks
each see the globals object that was active when they started.