Pure ASGI Database middleware.
Project description
asgi-sqlalchemy
ASGI Middleware that manages the lifespan of a database engine and a corresponding session, featuring no global state, and automatic rollbacks on unhandled exceptions. Includes FastAPI and Starlette integrations.
I wrote about my motivations for this library in-depth here, but the short version is that using the ASGI lifespan protocol, we can avoid the use of global state, making database access more predictable and easier to test/mock.
Installation:
uv add asgi-sqlalchemy
Usage:
FastAPI:
from contextlib import AsyncContextManager
from collections.abc import AsyncGenerator
from typing_extensions import TypedDict
from fastapi import FastAPI
from asgi_sqlalchemy import DatabaseContext, SessionMiddleware
from asgi_sqlalchemy.fastapi import SessionDependency
class AppState(TypedDict):
db: DatabaseContext
async def lifespan() -> AsyncGenerator[AppState]:
async with DatabaseContext(...) as db:
yield {"db": db}
app = FastAPI()
app.add_middleware(SessionMiddleware)
@app.get("/db")
async def handler(session: SessionDependency) -> str:
# do something with your async session!
Starlette:
from contextlib import AsyncContextManager
from collections.abc import AsyncGenerator
from typing_extensions import TypedDict
from starlette.applications import Starlette
from starlette.requests import Request
from starlette.responses import JSONResponse
from starlette.routing import Route
from asgi_sqlalchemy import DatabaseContext, SessionMiddleware
from asgi_sqlalchemy.starlette import get_session
class AppState(TypedDict):
db: DatabaseContext
async def lifespan() -> AsyncGenerator[AppState]:
async with DatabaseContext(...) as db:
yield {"db": db}
async def handler(request: Request) -> JSONResponse:
session = await get_session(request)
# do something with your async session!
app = Starlette(routes=[Route("/db", handler)], lifespan=lifespan)
app.add_middleware(SessionMiddleware)
Tests:
This library was explicitly designed to be easy to test without dependency overrides.
- For synchronous tests, use FastAPI's
TestClient. - For asynchronous tests, use HTTPX
AsyncClientwithASGITransport, and wrap the app withLifespanManagerso startup/shutdown events run. See the FastAPI docs: Async Tests – In Detail. - To “mock” your database, provide a custom lifespan in tests that yields the database object you want (real DB or test double). The middleware will inject a fresh session per request, no dependency overrides needed.
See complete examples in tests/test_fastapi.py and tests/test_starlette.py inside the tests/ folder.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file asgi_sqlalchemy-0.2.0.tar.gz.
File metadata
- Download URL: asgi_sqlalchemy-0.2.0.tar.gz
- Upload date:
- Size: 69.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.8.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
78ba8e5ea9cb5cb12142860a7af18da5c827fb26afcdf1dfeef4ac5a19d61bf5
|
|
| MD5 |
90a11a4a3fbd7579c6bb716e866ff0fb
|
|
| BLAKE2b-256 |
a9e9573c2ddfb2a2e163bf19a3cccd29572677fcf16c45ea31c1026a064c732b
|
File details
Details for the file asgi_sqlalchemy-0.2.0-py3-none-any.whl.
File metadata
- Download URL: asgi_sqlalchemy-0.2.0-py3-none-any.whl
- Upload date:
- Size: 6.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.8.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ab3cb98873a16d46edf169ddc19988aa5a011ae539779eef4a45d334b8492bd3
|
|
| MD5 |
8d0e53b8184a94971818a1a25a94fcbf
|
|
| BLAKE2b-256 |
67f500b814c1ab636c175b301f1005f7d2bd873dfca14e699e4bf6eef3499f14
|