-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathfastapi_sample.py
More file actions
120 lines (97 loc) · 3.38 KB
/
Copy pathfastapi_sample.py
File metadata and controls
120 lines (97 loc) · 3.38 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
import contextlib
import fastapi
import sqlalchemy as sa
import starlette.requests
from sqlalchemy.ext import asyncio as sa_asyncio
from rls import rls_sessioner
from rls import session
from test import database
from test import models
class SampleContextGetter(rls_sessioner.ContextGetter):
"""This is needed to generate the RLS context for each request."""
def get_context(
self, request: starlette.requests.Request
) -> models.SampleRlsContext:
account_id_param = request.query_params.get("account_id")
return models.SampleRlsContext(
account_id=int(account_id_param) if account_id_param is not None else None
)
# We then create a sessioner as a fastapi dependency to do the injection.
session_maker = sa.orm.sessionmaker(
class_=session.RlsSession, autoflush=False, autocommit=False
)
demo_sessioner = fastapi.Depends(
rls_sessioner.fastapi_dependency_function(
rls_sessioner.RlsSessioner(
sessionmaker=session_maker, context_getter=SampleContextGetter()
)
)
)
# Async variant using AsyncRlsSession.
async_session_maker = sa_asyncio.async_sessionmaker(
class_=session.AsyncRlsSession, autoflush=False, autocommit=False
)
async_demo_sessioner = fastapi.Depends(
rls_sessioner.async_fastapi_dependency_function(
rls_sessioner.AsyncRlsSessioner(
sessionmaker=async_session_maker, context_getter=SampleContextGetter()
)
)
)
@contextlib.asynccontextmanager
async def sample_database_setup(app: fastapi.FastAPI):
test_db = database.test_postgres_instance()
sync_engine = sa.create_engine(test_db.url)
async_engine = sa_asyncio.create_async_engine(test_db.url)
session_maker.configure(bind=sync_engine)
async_session_maker.configure(bind=async_engine)
yield
sync_engine.dispose()
await async_engine.dispose()
test_db.close()
app = fastapi.FastAPI(lifespan=sample_database_setup)
@app.get("/users")
def get_users(db=demo_sessioner, account_id: int | None = None) -> list[str]:
del account_id
# This query will already have the rls context set from the request.
result = db.execute(sa.select(models.User.username)).scalars()
data = list(result)
db.close()
return data
@app.get("/all_users")
def get_all_users(
db: session.RlsSession = demo_sessioner, account_id: int | None = None
) -> list[str]:
del account_id
with db.bypass_rls():
result = list(db.execute(sa.select(models.User.username)).scalars())
data = list(result)
db.close()
return data
@app.get("/async/users")
async def async_get_users(
db: session.AsyncRlsSession = async_demo_sessioner,
account_id: int | None = None,
) -> list[str]:
del account_id
# This query will already have the rls context set from the request.
result = (await db.execute(sa.select(models.User.username))).scalars()
return list(result)
@app.get("/async/all_users")
async def async_get_all_users(
db: session.AsyncRlsSession = async_demo_sessioner,
account_id: int | None = None,
) -> list[str]:
del account_id
async with db.bypass_rls():
result = list((await db.execute(sa.select(models.User.username))).scalars())
return result
if __name__ == "__main__":
import uvicorn
uvicorn.run(
"fastapi_sample:app",
host="0.0.0.0",
proxy_headers=True,
reload=True,
log_level="debug",
)