Skip to content

Commit 0a96bec

Browse files
committed
chore: update fastapi integration example
1 parent d711438 commit 0a96bec

3 files changed

Lines changed: 27 additions & 26 deletions

File tree

README.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,8 @@ finally:
383383

384384
```python
385385
from contextlib import asynccontextmanager
386+
from typing import Annotated
387+
386388
from fastapi import FastAPI, Depends
387389
from replane import AsyncReplane
388390

@@ -405,8 +407,11 @@ def get_replane() -> AsyncReplane:
405407
assert _replane is not None
406408
return _replane
407409

410+
# Define reusable dependency type
411+
Replane = Annotated[AsyncReplane, Depends(get_replane)]
412+
408413
@app.get("/items")
409-
async def get_items(replane: AsyncReplane = Depends(get_replane)):
414+
async def get_items(replane: Replane):
410415
max_items = replane.with_context({"plan": "free"}).configs["max-items"]
411416
return {"max_items": max_items}
412417
```

docs/source/frameworks.md

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ FastAPI's async nature makes it a perfect fit for the async Replane client.
1010

1111
```python
1212
from contextlib import asynccontextmanager
13+
from typing import Annotated
14+
1315
from fastapi import FastAPI, Depends
1416
from replane import AsyncReplane
1517

@@ -35,8 +37,11 @@ def get_replane() -> AsyncReplane:
3537
assert _replane is not None
3638
return _replane
3739

40+
# Define reusable dependency type
41+
Replane = Annotated[AsyncReplane, Depends(get_replane)]
42+
3843
@app.get("/items")
39-
async def get_items(replane: AsyncReplane = Depends(get_replane)):
44+
async def get_items(replane: Replane):
4045
max_items = replane.configs["max-items-per-page"]
4146
return {"max_items": max_items}
4247
```
@@ -47,10 +52,7 @@ async def get_items(replane: AsyncReplane = Depends(get_replane)):
4752
from fastapi import Request
4853

4954
@app.get("/features")
50-
async def get_features(
51-
request: Request,
52-
replane: AsyncReplane = Depends(get_replane),
53-
):
55+
async def get_features(request: Request, replane: Replane):
5456
# Build context from request/user
5557
user_client = replane.with_context({
5658
"user_id": request.state.user.id,
@@ -73,18 +75,20 @@ from replane._async import ContextualAsyncReplane
7375

7476
def get_replane_with_context(
7577
request: Request,
76-
replane: AsyncReplane = Depends(get_replane),
78+
replane: Replane,
7779
) -> ContextualAsyncReplane:
7880
context = {}
7981
if hasattr(request.state, "user"):
8082
context["user_id"] = request.state.user.id
8183
context["plan"] = request.state.user.plan
8284
return replane.with_context(context)
8385

86+
ReplaneWithContext = Annotated[ContextualAsyncReplane, Depends(get_replane_with_context)]
87+
8488
@app.get("/dashboard")
85-
async def dashboard(config: ContextualAsyncReplane = Depends(get_replane_with_context)):
89+
async def dashboard(replane: ReplaneWithContext):
8690
# Context is automatically included
87-
show_analytics = config.configs["show-analytics"]
91+
show_analytics = replane.configs["show-analytics"]
8892
return {"show_analytics": show_analytics}
8993
```
9094

examples/fastapi-integration/app.py

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,11 @@ def get_user_context(
7272
}
7373

7474

75+
# Define reusable dependency types (recommended FastAPI pattern)
76+
Replane = Annotated[AsyncReplane, Depends(get_replane)]
77+
UserContext = Annotated[dict, Depends(get_user_context)]
78+
79+
7580
# Response models
7681
class WelcomeResponse(BaseModel):
7782
message: str
@@ -108,10 +113,7 @@ async def check_maintenance_mode(request: Request, call_next):
108113

109114

110115
@app.get("/", response_model=WelcomeResponse)
111-
async def index(
112-
replane: Annotated[AsyncReplane, Depends(get_replane)],
113-
ctx: Annotated[dict, Depends(get_user_context)],
114-
):
116+
async def index(replane: Replane, ctx: UserContext):
115117
"""Homepage with feature flag check."""
116118
user_client = replane.with_context(ctx)
117119
new_dashboard = user_client.configs["new-dashboard-enabled"]
@@ -123,10 +125,7 @@ async def index(
123125

124126

125127
@app.get("/api/items", response_model=ItemsResponse)
126-
async def get_items(
127-
replane: Annotated[AsyncReplane, Depends(get_replane)],
128-
ctx: Annotated[dict, Depends(get_user_context)],
129-
):
128+
async def get_items(replane: Replane, ctx: UserContext):
130129
"""List items with configurable rate limiting."""
131130
user_client = replane.with_context(ctx)
132131
rate_limit = user_client.configs["rate-limit"]
@@ -145,11 +144,7 @@ async def get_items(
145144

146145

147146
@app.post("/api/upload", response_model=UploadResponse)
148-
async def upload(
149-
request: Request,
150-
replane: Annotated[AsyncReplane, Depends(get_replane)],
151-
ctx: Annotated[dict, Depends(get_user_context)],
152-
):
147+
async def upload(request: Request, replane: Replane, ctx: UserContext):
153148
"""Upload endpoint with configurable size limit."""
154149
user_client = replane.with_context(ctx)
155150
max_size_mb = user_client.configs["max-upload-size-mb"]
@@ -170,10 +165,7 @@ async def upload(
170165

171166

172167
@app.get("/api/config", response_model=ConfigResponse)
173-
async def get_config(
174-
replane: Annotated[AsyncReplane, Depends(get_replane)],
175-
ctx: Annotated[dict, Depends(get_user_context)],
176-
):
168+
async def get_config(replane: Replane, ctx: UserContext):
177169
"""Debug endpoint to view current config values."""
178170
user_client = replane.with_context(ctx)
179171
return ConfigResponse(

0 commit comments

Comments
 (0)