Sanic#
SQLSpec provides a Sanic extension that uses Sanic-native application and
request context. Connection pools are stored on app.ctx during the worker
lifecycle, and request-scoped connections and sessions are stored on
request.ctx.
Installation#
Install SQLSpec with the Sanic extra:
uv add "sqlspec[sanic]"
pip install "sqlspec[sanic]"
poetry add "sqlspec[sanic]"
pdm add "sqlspec[sanic]"
Basic Setup#
Create a SQLSpec instance, register your database config, and attach
SQLSpecPlugin to your Sanic app. Configure Sanic-specific options under
extension_config["sanic"].
sanic basic setup#from sanic import Request, Sanic, response
from sanic.response import HTTPResponse
from sqlspec import SQLSpec
from sqlspec.adapters.aiosqlite import AiosqliteConfig, AiosqliteDriver
from sqlspec.extensions.sanic import SQLSpecPlugin
sqlspec = SQLSpec()
sqlspec.add_config(
AiosqliteConfig(
connection_config={"database": ":memory:"},
extension_config={"sanic": {"commit_mode": "manual", "session_key": "db"}},
)
)
db_plugin = SQLSpecPlugin(sqlspec)
app = Sanic("SQLSpecSanicBasicExample")
@app.get("/health")
async def health(request: Request) -> HTTPResponse:
db: AiosqliteDriver = db_plugin.get_session(request, "db")
result = await db.execute("select 1 as ok")
return response.json(result.one())
db_plugin.init_app(app)
Transaction Modes#
Sanic supports the same transaction modes as the other request-oriented framework integrations:
manualSQLSpec manages connection scope only. Your handler commits or rolls back.
autocommitSQLSpec commits 2xx responses and rolls back other responses.
autocommit_include_redirectSQLSpec commits 2xx and 3xx responses and rolls back other responses.
Extra commit and rollback statuses are configured per database config.
sanic commit modes#from sanic import Request, Sanic, response
from sanic.response import HTTPResponse
from sqlspec import SQLSpec
from sqlspec.adapters.aiosqlite import AiosqliteConfig
from sqlspec.extensions.sanic import SQLSpecPlugin
sqlspec = SQLSpec()
sqlspec.add_config(
AiosqliteConfig(
connection_config={"database": "app.db"},
extension_config={
"sanic": {"commit_mode": "autocommit", "extra_rollback_statuses": {409}, "session_key": "db"}
},
)
)
db_plugin = SQLSpecPlugin(sqlspec)
app = Sanic("SQLSpecSanicCommitModesExample")
@app.post("/users")
async def create_user(request: Request) -> HTTPResponse:
db = db_plugin.get_session(request, "db")
await db.execute("insert into users (name) values (:name)", name=request.json["name"])
return response.json({"created": True}, status=201)
db_plugin.init_app(app)
Multiple Databases#
For multiple databases, give each config unique connection_key,
pool_key, and session_key values. The plugin can then look up sessions
by session key.
sanic multi database#from sanic import Request, Sanic, response
from sanic.response import HTTPResponse
from sqlspec import SQLSpec
from sqlspec.adapters.aiosqlite import AiosqliteConfig, AiosqliteDriver
from sqlspec.adapters.sqlite import SqliteConfig, SqliteDriver
from sqlspec.extensions.sanic import SQLSpecPlugin
sqlspec = SQLSpec()
sqlspec.add_config(
AiosqliteConfig(
bind_key="primary",
connection_config={"database": "primary.db"},
extension_config={
"sanic": {
"connection_key": "primary_connection",
"pool_key": "primary_pool",
"session_key": "primary_db",
}
},
)
)
sqlspec.add_config(
SqliteConfig(
bind_key="analytics",
connection_config={"database": "analytics.db"},
extension_config={
"sanic": {
"connection_key": "analytics_connection",
"pool_key": "analytics_pool",
"session_key": "analytics_db",
}
},
)
)
db_plugin = SQLSpecPlugin(sqlspec)
app = Sanic("SQLSpecSanicMultiDatabaseExample")
@app.get("/report")
async def report(request: Request) -> HTTPResponse:
primary: AiosqliteDriver = db_plugin.get_session(request, "primary_db")
analytics: SqliteDriver = db_plugin.get_session(request, "analytics_db")
users = await primary.select("select 1 as id, 'Alice' as name")
metrics = analytics.select("select 'active_users' as name, 100 as value")
return response.json({"users": users, "metrics": metrics})
db_plugin.init_app(app)
Request Access#
Use plugin.get_session(request, key=None) for driver sessions and
plugin.get_connection(request, key=None) for raw connection access. The
default key is the first registered config's session_key; passing a key is
recommended when an app has multiple configs.
get_connection_from_request(request, config_state) and
get_or_create_session(request, config_state) are lower-level helpers for
custom integrations.
disable_di#
Set disable_di=True when another dependency injection system owns
request-scoped connection management. SQLSpec still creates and closes pools
on Sanic startup and shutdown, but it does not put connections or sessions on
request.ctx.
sanic disable di#from sanic import Request, Sanic, response
from sanic.response import HTTPResponse
from sqlspec import SQLSpec
from sqlspec.adapters.aiosqlite import AiosqliteConfig
from sqlspec.extensions.sanic import SQLSpecPlugin
sqlspec = SQLSpec()
config = AiosqliteConfig(
connection_config={"database": "app.db"},
extension_config={"sanic": {"disable_di": True, "pool_key": "db_pool"}},
)
sqlspec.add_config(config)
db_plugin = SQLSpecPlugin(sqlspec)
app = Sanic("SQLSpecSanicDisableDIExample")
@app.get("/health")
async def health(request: Request) -> HTTPResponse:
async with config.provide_connection(request.app.ctx.db_pool) as connection:
db = config.driver_type(connection=connection, statement_config=config.statement_config)
result = await db.execute("select 1 as ok")
return response.json(result.one())
db_plugin.init_app(app)
Correlation IDs and SQLCommenter#
Set enable_correlation_middleware=True to extract request correlation IDs
from headers and return X-Correlation-ID on the response. The active value
is also available from request.ctx.correlation_id and
CorrelationContext during the request.
SQLCommenter is enabled when the driver StatementConfig has
enable_sqlcommenter=True and the Sanic config keeps
enable_sqlcommenter_middleware=True. Request attributes include
framework="sanic", route, and action.
sanic observability#from sanic import Request, Sanic, response
from sanic.response import HTTPResponse
from sqlspec import SQLSpec
from sqlspec.adapters.aiosqlite import AiosqliteConfig
from sqlspec.core import StatementConfig
from sqlspec.extensions.sanic import SQLSpecPlugin
sqlspec = SQLSpec()
sqlspec.add_config(
AiosqliteConfig(
connection_config={"database": "app.db"},
statement_config=StatementConfig(enable_sqlcommenter=True),
extension_config={
"sanic": {
"enable_correlation_middleware": True,
"enable_sqlcommenter_middleware": True,
"session_key": "db",
}
},
)
)
db_plugin = SQLSpecPlugin(sqlspec)
app = Sanic("SQLSpecSanicObservabilityExample")
@app.get("/health")
async def health(request: Request) -> HTTPResponse:
return response.json({"correlation_id": request.ctx.correlation_id})
db_plugin.init_app(app)