This design follows FastAPI best practices:
import asyncpg
from contextlib import asynccontextmanager
from typing import Callable
from os import getenv # convert to pydantic_settings
import air
DATABASE_URL = getenv('DATABASE_URL')
def make_lifespan(dsn: str, *, min_size: int = 1, max_size: int = 10) -> Callable:
@asynccontextmanager
async def lifespan(app: Air):
async with asyncpg.create_pool(
dsn=dsn,
min_size=min_size,
max_size=max_size,
) as pool:
yield {'pool': pool}
return lifespan
lifespan = make_lifespan(DATABASE_URL)
app = air.Air(lifespan=lifespan)Usage:
@app.page
async def index(request: Request):
async with request.state.pool.acquire() as conn:
users = await conn.fetchmany(
"SELECT * FROM users;"
)
return *[air.P(u) for x in users]