@martinffx/atelier 2.0.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/README.md +94 -253
- package/package.json +1 -1
- package/skills/{spec-orchestrator → atelier-orchestrator}/SKILL.md +3 -3
- package/skills/atelier-setup/SKILL.md +80 -0
- package/skills/code-review/references/reviewers.md +3 -3
- package/skills/code-review/references/rq.md +6 -6
- package/skills/spec-brainstorm/SKILL.md +5 -5
- package/skills/spec-implement/SKILL.md +2 -3
- package/skills/spec-plan/SKILL.md +21 -29
- package/skills/spec-plan/references/plan_template.md +77 -0
- package/skills/python-architecture/SKILL.md +0 -148
- package/skills/python-architecture/references/data-modeling.md +0 -558
- package/skills/python-architecture/references/ddd.md +0 -569
- package/skills/python-architecture/references/functional-core.md +0 -337
- package/skills/python-build-tools/SKILL.md +0 -153
- package/skills/python-build-tools/references/basedpyright.md +0 -321
- package/skills/python-build-tools/references/ruff.md +0 -225
- package/skills/python-build-tools/references/uv.md +0 -257
- package/skills/python-fastapi/SKILL.md +0 -184
- package/skills/python-fastapi/references/api-design.md +0 -563
- package/skills/python-fastapi/references/dependencies.md +0 -479
- package/skills/python-fastapi/references/middleware.md +0 -475
- package/skills/python-fastapi/references/validation.md +0 -497
- package/skills/python-modern-python/SKILL.md +0 -201
- package/skills/python-modern-python/references/async.md +0 -76
- package/skills/python-modern-python/references/pattern-matching.md +0 -89
- package/skills/python-modern-python/references/typing.md +0 -96
- package/skills/python-monorepo/SKILL.md +0 -146
- package/skills/python-monorepo/references/docker.md +0 -515
- package/skills/python-monorepo/references/namespace-packages.md +0 -426
- package/skills/python-monorepo/references/workspace-config.md +0 -341
- package/skills/python-sqlalchemy/SKILL.md +0 -119
- package/skills/python-sqlalchemy/references/async.md +0 -51
- package/skills/python-sqlalchemy/references/models.md +0 -67
- package/skills/python-sqlalchemy/references/queries.md +0 -57
- package/skills/python-temporal/SKILL.md +0 -128
- package/skills/python-temporal/references/patterns.md +0 -87
- package/skills/python-temporal/references/testing.md +0 -54
- package/skills/python-testing/SKILL.md +0 -161
- package/skills/python-testing/references/boundaries.md +0 -449
- package/skills/python-testing/references/mocking.md +0 -449
- package/skills/python-testing/references/pytest.md +0 -524
- package/skills/typescript-api-design/SKILL.md +0 -396
- package/skills/typescript-api-design/references/error-responses.md +0 -469
- package/skills/typescript-build-tools/SKILL.md +0 -447
- package/skills/typescript-build-tools/references/biome.md +0 -436
- package/skills/typescript-build-tools/references/bun.md +0 -432
- package/skills/typescript-build-tools/references/turborepo.md +0 -426
- package/skills/typescript-build-tools/references/vitest.md +0 -518
- package/skills/typescript-drizzle-orm/SKILL.md +0 -398
- package/skills/typescript-drizzle-orm/references/cloudflare.md +0 -392
- package/skills/typescript-drizzle-orm/references/entity-pattern.md +0 -412
- package/skills/typescript-drizzle-orm/references/postgresql.md +0 -191
- package/skills/typescript-drizzle-orm/references/repository-pattern.md +0 -479
- package/skills/typescript-drizzle-orm/references/sqlite.md +0 -291
- package/skills/typescript-dynamodb-toolbox/SKILL.md +0 -370
- package/skills/typescript-dynamodb-toolbox/references/entity-layer.md +0 -574
- package/skills/typescript-dynamodb-toolbox/references/error-handling.md +0 -495
- package/skills/typescript-dynamodb-toolbox/references/modeling.md +0 -332
- package/skills/typescript-dynamodb-toolbox/references/repository-layer.md +0 -631
- package/skills/typescript-dynamodb-toolbox/references/testing.md +0 -718
- package/skills/typescript-dynamodb-toolbox/references/transactions.md +0 -423
- package/skills/typescript-effect-ts/SKILL.md +0 -341
- package/skills/typescript-effect-ts/references/core.md +0 -412
- package/skills/typescript-effect-ts/references/error-handling.md +0 -468
- package/skills/typescript-effect-ts/references/resources.md +0 -476
- package/skills/typescript-effect-ts/references/schema.md +0 -536
- package/skills/typescript-effect-ts/references/services.md +0 -461
- package/skills/typescript-fastify/SKILL.md +0 -405
- package/skills/typescript-fastify/references/plugins.md +0 -329
- package/skills/typescript-fastify/references/typeid.md +0 -315
- package/skills/typescript-functional-patterns/SKILL.md +0 -402
- package/skills/typescript-functional-patterns/references/adts.md +0 -497
- package/skills/typescript-functional-patterns/references/branded-types.md +0 -542
- package/skills/typescript-functional-patterns/references/migration-guide.md +0 -695
- package/skills/typescript-functional-patterns/references/option-result.md +0 -585
- package/skills/typescript-testing/SKILL.md +0 -353
- package/skills/typescript-testing/references/mocking.md +0 -675
- package/skills/typescript-testing/references/msw.md +0 -852
- package/skills/typescript-testing/references/snapshot-testing.md +0 -774
|
@@ -1,479 +0,0 @@
|
|
|
1
|
-
# Dependency Injection in FastAPI
|
|
2
|
-
|
|
3
|
-
FastAPI's dependency injection system manages shared resources, authentication, database sessions, and cross-cutting concerns.
|
|
4
|
-
|
|
5
|
-
## Basic Dependencies
|
|
6
|
-
|
|
7
|
-
### Function Dependencies
|
|
8
|
-
|
|
9
|
-
```python
|
|
10
|
-
from fastapi import Depends
|
|
11
|
-
|
|
12
|
-
def get_db():
|
|
13
|
-
"""Simple dependency"""
|
|
14
|
-
db = Database()
|
|
15
|
-
try:
|
|
16
|
-
yield db
|
|
17
|
-
finally:
|
|
18
|
-
db.close()
|
|
19
|
-
|
|
20
|
-
@app.get("/users")
|
|
21
|
-
def list_users(db: Database = Depends(get_db)):
|
|
22
|
-
"""db injected automatically"""
|
|
23
|
-
return db.query(User).all()
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
### Class Dependencies
|
|
27
|
-
|
|
28
|
-
```python
|
|
29
|
-
class DatabaseSession:
|
|
30
|
-
def __init__(self):
|
|
31
|
-
self.db = Database()
|
|
32
|
-
|
|
33
|
-
def __enter__(self):
|
|
34
|
-
return self.db
|
|
35
|
-
|
|
36
|
-
def __exit__(self, *args):
|
|
37
|
-
self.db.close()
|
|
38
|
-
|
|
39
|
-
@app.get("/users")
|
|
40
|
-
def list_users(db: Database = Depends(DatabaseSession)):
|
|
41
|
-
return db.query(User).all()
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
## Nested Dependencies
|
|
45
|
-
|
|
46
|
-
Dependencies can depend on other dependencies:
|
|
47
|
-
|
|
48
|
-
```python
|
|
49
|
-
def get_db():
|
|
50
|
-
db = Database()
|
|
51
|
-
try:
|
|
52
|
-
yield db
|
|
53
|
-
finally:
|
|
54
|
-
db.close()
|
|
55
|
-
|
|
56
|
-
def get_user_repo(db: Database = Depends(get_db)):
|
|
57
|
-
"""Depends on get_db"""
|
|
58
|
-
return UserRepository(db)
|
|
59
|
-
|
|
60
|
-
@app.get("/users")
|
|
61
|
-
def list_users(repo: UserRepository = Depends(get_user_repo)):
|
|
62
|
-
"""repo injected with db already provided"""
|
|
63
|
-
return repo.find_all()
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
## Authentication Dependencies
|
|
67
|
-
|
|
68
|
-
### Token Extraction
|
|
69
|
-
|
|
70
|
-
```python
|
|
71
|
-
from fastapi import Depends, HTTPException, Header
|
|
72
|
-
|
|
73
|
-
def get_token(authorization: str = Header()):
|
|
74
|
-
"""Extract token from header"""
|
|
75
|
-
if not authorization.startswith("Bearer "):
|
|
76
|
-
raise HTTPException(status_code=401, detail="Invalid authorization header")
|
|
77
|
-
return authorization[7:] # Remove "Bearer " prefix
|
|
78
|
-
|
|
79
|
-
@app.get("/me")
|
|
80
|
-
def get_current_user_profile(token: str = Depends(get_token)):
|
|
81
|
-
user = decode_token(token)
|
|
82
|
-
return user
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
### Current User Dependency
|
|
86
|
-
|
|
87
|
-
```python
|
|
88
|
-
from fastapi import Depends, HTTPException
|
|
89
|
-
from fastapi.security import HTTPBearer
|
|
90
|
-
|
|
91
|
-
security = HTTPBearer()
|
|
92
|
-
|
|
93
|
-
def get_current_user(
|
|
94
|
-
credentials: HTTPAuthorizationCredentials = Depends(security),
|
|
95
|
-
db: Database = Depends(get_db),
|
|
96
|
-
) -> User:
|
|
97
|
-
"""Get authenticated user"""
|
|
98
|
-
token = credentials.credentials
|
|
99
|
-
|
|
100
|
-
# Decode token
|
|
101
|
-
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
|
|
102
|
-
user_id = payload.get("user_id")
|
|
103
|
-
|
|
104
|
-
if not user_id:
|
|
105
|
-
raise HTTPException(status_code=401, detail="Invalid token")
|
|
106
|
-
|
|
107
|
-
# Get user from database
|
|
108
|
-
user = db.query(User).filter(User.id == user_id).first()
|
|
109
|
-
if not user:
|
|
110
|
-
raise HTTPException(status_code=401, detail="User not found")
|
|
111
|
-
|
|
112
|
-
return user
|
|
113
|
-
|
|
114
|
-
@app.get("/me")
|
|
115
|
-
def get_profile(current_user: User = Depends(get_current_user)):
|
|
116
|
-
"""current_user injected"""
|
|
117
|
-
return current_user
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
### Optional Authentication
|
|
121
|
-
|
|
122
|
-
```python
|
|
123
|
-
from typing import Optional
|
|
124
|
-
|
|
125
|
-
def get_current_user_optional(
|
|
126
|
-
credentials: Optional[HTTPAuthorizationCredentials] = Depends(security),
|
|
127
|
-
) -> User | None:
|
|
128
|
-
"""Optional authentication"""
|
|
129
|
-
if not credentials:
|
|
130
|
-
return None
|
|
131
|
-
|
|
132
|
-
try:
|
|
133
|
-
return decode_and_get_user(credentials.credentials)
|
|
134
|
-
except:
|
|
135
|
-
return None
|
|
136
|
-
|
|
137
|
-
@app.get("/posts")
|
|
138
|
-
def list_posts(current_user: User | None = Depends(get_current_user_optional)):
|
|
139
|
-
"""Works with or without authentication"""
|
|
140
|
-
if current_user:
|
|
141
|
-
return get_posts_for_user(current_user)
|
|
142
|
-
return get_public_posts()
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
## Permission Dependencies
|
|
146
|
-
|
|
147
|
-
```python
|
|
148
|
-
from enum import Enum
|
|
149
|
-
|
|
150
|
-
class Permission(Enum):
|
|
151
|
-
READ = "read"
|
|
152
|
-
WRITE = "write"
|
|
153
|
-
ADMIN = "admin"
|
|
154
|
-
|
|
155
|
-
def require_permission(permission: Permission):
|
|
156
|
-
"""Factory function returning dependency"""
|
|
157
|
-
def check_permission(current_user: User = Depends(get_current_user)):
|
|
158
|
-
if permission not in current_user.permissions:
|
|
159
|
-
raise HTTPException(status_code=403, detail="Permission denied")
|
|
160
|
-
return current_user
|
|
161
|
-
return check_permission
|
|
162
|
-
|
|
163
|
-
# Usage
|
|
164
|
-
@app.post("/users")
|
|
165
|
-
def create_user(
|
|
166
|
-
user: CreateUserRequest,
|
|
167
|
-
current_user: User = Depends(require_permission(Permission.ADMIN)),
|
|
168
|
-
):
|
|
169
|
-
"""Requires ADMIN permission"""
|
|
170
|
-
...
|
|
171
|
-
|
|
172
|
-
@app.get("/users")
|
|
173
|
-
def list_users(
|
|
174
|
-
current_user: User = Depends(require_permission(Permission.READ)),
|
|
175
|
-
):
|
|
176
|
-
"""Requires READ permission"""
|
|
177
|
-
...
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
## Database Session Management
|
|
181
|
-
|
|
182
|
-
### SQLAlchemy Session
|
|
183
|
-
|
|
184
|
-
```python
|
|
185
|
-
from sqlalchemy.orm import Session, sessionmaker
|
|
186
|
-
|
|
187
|
-
SessionLocal = sessionmaker(bind=engine)
|
|
188
|
-
|
|
189
|
-
def get_db() -> Session:
|
|
190
|
-
"""Database session dependency"""
|
|
191
|
-
db = SessionLocal()
|
|
192
|
-
try:
|
|
193
|
-
yield db
|
|
194
|
-
finally:
|
|
195
|
-
db.close()
|
|
196
|
-
|
|
197
|
-
@app.get("/users")
|
|
198
|
-
def list_users(db: Session = Depends(get_db)):
|
|
199
|
-
return db.query(UserModel).all()
|
|
200
|
-
```
|
|
201
|
-
|
|
202
|
-
### With Transaction Management
|
|
203
|
-
|
|
204
|
-
```python
|
|
205
|
-
from contextlib import contextmanager
|
|
206
|
-
|
|
207
|
-
@contextmanager
|
|
208
|
-
def get_db_with_transaction():
|
|
209
|
-
"""Database session with automatic transaction"""
|
|
210
|
-
db = SessionLocal()
|
|
211
|
-
try:
|
|
212
|
-
yield db
|
|
213
|
-
db.commit()
|
|
214
|
-
except Exception:
|
|
215
|
-
db.rollback()
|
|
216
|
-
raise
|
|
217
|
-
finally:
|
|
218
|
-
db.close()
|
|
219
|
-
|
|
220
|
-
@app.post("/users")
|
|
221
|
-
def create_user(
|
|
222
|
-
user: CreateUserRequest,
|
|
223
|
-
db: Session = Depends(get_db_with_transaction),
|
|
224
|
-
):
|
|
225
|
-
"""Transaction automatically committed or rolled back"""
|
|
226
|
-
new_user = UserModel(**user.model_dump())
|
|
227
|
-
db.add(new_user)
|
|
228
|
-
# Commit happens automatically on success
|
|
229
|
-
return new_user
|
|
230
|
-
```
|
|
231
|
-
|
|
232
|
-
## Dependency Classes
|
|
233
|
-
|
|
234
|
-
Classes can be dependencies:
|
|
235
|
-
|
|
236
|
-
```python
|
|
237
|
-
from fastapi import Depends, HTTPException
|
|
238
|
-
|
|
239
|
-
class UserService:
|
|
240
|
-
def __init__(self, db: Session = Depends(get_db)):
|
|
241
|
-
self.db = db
|
|
242
|
-
self.repo = UserRepository(db)
|
|
243
|
-
|
|
244
|
-
def get_user(self, user_id: int) -> User:
|
|
245
|
-
user = self.repo.find_by_id(user_id)
|
|
246
|
-
if not user:
|
|
247
|
-
raise HTTPException(status_code=404, detail="User not found")
|
|
248
|
-
return user
|
|
249
|
-
|
|
250
|
-
def create_user(self, data: CreateUserRequest) -> User:
|
|
251
|
-
user = User.from_request(data)
|
|
252
|
-
return self.repo.save(user)
|
|
253
|
-
|
|
254
|
-
@app.get("/users/{user_id}")
|
|
255
|
-
def get_user(
|
|
256
|
-
user_id: int,
|
|
257
|
-
service: UserService = Depends(),
|
|
258
|
-
):
|
|
259
|
-
"""UserService injected with db already provided"""
|
|
260
|
-
return service.get_user(user_id)
|
|
261
|
-
```
|
|
262
|
-
|
|
263
|
-
## Global Dependencies
|
|
264
|
-
|
|
265
|
-
Apply dependencies to all routes:
|
|
266
|
-
|
|
267
|
-
```python
|
|
268
|
-
app = FastAPI(dependencies=[Depends(get_current_user)])
|
|
269
|
-
|
|
270
|
-
# All routes require authentication
|
|
271
|
-
@app.get("/users")
|
|
272
|
-
def list_users():
|
|
273
|
-
...
|
|
274
|
-
|
|
275
|
-
@app.get("/products")
|
|
276
|
-
def list_products():
|
|
277
|
-
...
|
|
278
|
-
```
|
|
279
|
-
|
|
280
|
-
### Router-level Dependencies
|
|
281
|
-
|
|
282
|
-
```python
|
|
283
|
-
router = APIRouter(
|
|
284
|
-
prefix="/admin",
|
|
285
|
-
dependencies=[Depends(require_permission(Permission.ADMIN))],
|
|
286
|
-
)
|
|
287
|
-
|
|
288
|
-
# All routes in this router require ADMIN permission
|
|
289
|
-
@router.get("/users")
|
|
290
|
-
def list_all_users():
|
|
291
|
-
...
|
|
292
|
-
|
|
293
|
-
@router.delete("/users/{user_id}")
|
|
294
|
-
def delete_user(user_id: int):
|
|
295
|
-
...
|
|
296
|
-
```
|
|
297
|
-
|
|
298
|
-
## Caching Dependencies
|
|
299
|
-
|
|
300
|
-
Use `use_cache=False` to disable dependency caching:
|
|
301
|
-
|
|
302
|
-
```python
|
|
303
|
-
def get_timestamp():
|
|
304
|
-
"""Called once per request by default"""
|
|
305
|
-
return datetime.now()
|
|
306
|
-
|
|
307
|
-
@app.get("/time")
|
|
308
|
-
def get_time(
|
|
309
|
-
ts1: datetime = Depends(get_timestamp),
|
|
310
|
-
ts2: datetime = Depends(get_timestamp),
|
|
311
|
-
):
|
|
312
|
-
# ts1 and ts2 are the same (cached)
|
|
313
|
-
return {"ts1": ts1, "ts2": ts2}
|
|
314
|
-
|
|
315
|
-
@app.get("/time-no-cache")
|
|
316
|
-
def get_time_no_cache(
|
|
317
|
-
ts1: datetime = Depends(get_timestamp, use_cache=False),
|
|
318
|
-
ts2: datetime = Depends(get_timestamp, use_cache=False),
|
|
319
|
-
):
|
|
320
|
-
# ts1 and ts2 are different (not cached)
|
|
321
|
-
return {"ts1": ts1, "ts2": ts2}
|
|
322
|
-
```
|
|
323
|
-
|
|
324
|
-
## Dependency Override (Testing)
|
|
325
|
-
|
|
326
|
-
Override dependencies in tests:
|
|
327
|
-
|
|
328
|
-
```python
|
|
329
|
-
from fastapi.testclient import TestClient
|
|
330
|
-
|
|
331
|
-
def get_db_override():
|
|
332
|
-
"""Test database"""
|
|
333
|
-
return TestDatabase()
|
|
334
|
-
|
|
335
|
-
app.dependency_overrides[get_db] = get_db_override
|
|
336
|
-
|
|
337
|
-
client = TestClient(app)
|
|
338
|
-
|
|
339
|
-
# Tests use TestDatabase instead of real database
|
|
340
|
-
response = client.get("/users")
|
|
341
|
-
```
|
|
342
|
-
|
|
343
|
-
## Query and Path Parameters as Dependencies
|
|
344
|
-
|
|
345
|
-
```python
|
|
346
|
-
from fastapi import Query, Path
|
|
347
|
-
|
|
348
|
-
def pagination(
|
|
349
|
-
page: int = Query(default=1, ge=1),
|
|
350
|
-
page_size: int = Query(default=10, ge=1, le=100),
|
|
351
|
-
):
|
|
352
|
-
"""Pagination dependency"""
|
|
353
|
-
return {"skip": (page - 1) * page_size, "limit": page_size}
|
|
354
|
-
|
|
355
|
-
@app.get("/users")
|
|
356
|
-
def list_users(
|
|
357
|
-
pagination: dict = Depends(pagination),
|
|
358
|
-
db: Session = Depends(get_db),
|
|
359
|
-
):
|
|
360
|
-
return db.query(User).offset(pagination["skip"]).limit(pagination["limit"]).all()
|
|
361
|
-
```
|
|
362
|
-
|
|
363
|
-
## Header Dependencies
|
|
364
|
-
|
|
365
|
-
```python
|
|
366
|
-
def verify_api_key(x_api_key: str = Header()):
|
|
367
|
-
"""Verify API key from header"""
|
|
368
|
-
if x_api_key != VALID_API_KEY:
|
|
369
|
-
raise HTTPException(status_code=401, detail="Invalid API key")
|
|
370
|
-
return x_api_key
|
|
371
|
-
|
|
372
|
-
@app.get("/protected")
|
|
373
|
-
def protected_route(api_key: str = Depends(verify_api_key)):
|
|
374
|
-
return {"message": "Access granted"}
|
|
375
|
-
```
|
|
376
|
-
|
|
377
|
-
## Cookie Dependencies
|
|
378
|
-
|
|
379
|
-
```python
|
|
380
|
-
from fastapi import Cookie
|
|
381
|
-
|
|
382
|
-
def get_session(session_id: str | None = Cookie(default=None)):
|
|
383
|
-
"""Get session from cookie"""
|
|
384
|
-
if not session_id:
|
|
385
|
-
raise HTTPException(status_code=401, detail="No session")
|
|
386
|
-
session = get_session_from_cache(session_id)
|
|
387
|
-
if not session:
|
|
388
|
-
raise HTTPException(status_code=401, detail="Invalid session")
|
|
389
|
-
return session
|
|
390
|
-
|
|
391
|
-
@app.get("/dashboard")
|
|
392
|
-
def dashboard(session: Session = Depends(get_session)):
|
|
393
|
-
return {"user": session.user}
|
|
394
|
-
```
|
|
395
|
-
|
|
396
|
-
## Application State Dependencies
|
|
397
|
-
|
|
398
|
-
```python
|
|
399
|
-
from fastapi import Request
|
|
400
|
-
|
|
401
|
-
def get_redis(request: Request):
|
|
402
|
-
"""Access app state"""
|
|
403
|
-
return request.app.state.redis
|
|
404
|
-
|
|
405
|
-
def get_cache(request: Request):
|
|
406
|
-
return request.app.state.cache
|
|
407
|
-
|
|
408
|
-
@app.get("/cached")
|
|
409
|
-
def get_cached_data(
|
|
410
|
-
cache = Depends(get_cache),
|
|
411
|
-
redis = Depends(get_redis),
|
|
412
|
-
):
|
|
413
|
-
...
|
|
414
|
-
```
|
|
415
|
-
|
|
416
|
-
## Advanced Patterns
|
|
417
|
-
|
|
418
|
-
### Factory Dependencies
|
|
419
|
-
|
|
420
|
-
```python
|
|
421
|
-
from typing import Type
|
|
422
|
-
|
|
423
|
-
def create_repository(model: Type):
|
|
424
|
-
"""Factory for creating repository dependencies"""
|
|
425
|
-
def get_repository(db: Session = Depends(get_db)):
|
|
426
|
-
return Repository(db, model)
|
|
427
|
-
return get_repository
|
|
428
|
-
|
|
429
|
-
# Create specific repository dependencies
|
|
430
|
-
get_user_repo = create_repository(UserModel)
|
|
431
|
-
get_product_repo = create_repository(ProductModel)
|
|
432
|
-
|
|
433
|
-
@app.get("/users")
|
|
434
|
-
def list_users(repo = Depends(get_user_repo)):
|
|
435
|
-
return repo.find_all()
|
|
436
|
-
```
|
|
437
|
-
|
|
438
|
-
### Async Dependencies
|
|
439
|
-
|
|
440
|
-
```python
|
|
441
|
-
async def get_async_db():
|
|
442
|
-
"""Async dependency"""
|
|
443
|
-
async with AsyncDatabase() as db:
|
|
444
|
-
yield db
|
|
445
|
-
|
|
446
|
-
@app.get("/users")
|
|
447
|
-
async def list_users(db: AsyncDatabase = Depends(get_async_db)):
|
|
448
|
-
return await db.query(User).all()
|
|
449
|
-
```
|
|
450
|
-
|
|
451
|
-
## Best Practices
|
|
452
|
-
|
|
453
|
-
1. **Use dependencies for shared resources**: Database, cache, external services
|
|
454
|
-
2. **Nest dependencies**: Build complex dependencies from simple ones
|
|
455
|
-
3. **Class dependencies for services**: Encapsulate business logic
|
|
456
|
-
4. **Factory functions for permissions**: Reusable permission checks
|
|
457
|
-
5. **Override in tests**: Swap real dependencies with test doubles
|
|
458
|
-
6. **Type hints are required**: FastAPI needs types for injection
|
|
459
|
-
7. **Use `yield` for cleanup**: Ensure resources are released
|
|
460
|
-
|
|
461
|
-
## Summary
|
|
462
|
-
|
|
463
|
-
**Dependency types:**
|
|
464
|
-
- Function dependencies (with `yield` for cleanup)
|
|
465
|
-
- Class dependencies (automatic instantiation)
|
|
466
|
-
- Nested dependencies (compose from simpler ones)
|
|
467
|
-
|
|
468
|
-
**Common use cases:**
|
|
469
|
-
- Database sessions
|
|
470
|
-
- Authentication/authorization
|
|
471
|
-
- Pagination parameters
|
|
472
|
-
- External service clients
|
|
473
|
-
- Caching
|
|
474
|
-
|
|
475
|
-
**Advanced features:**
|
|
476
|
-
- Factory functions (reusable patterns)
|
|
477
|
-
- Router/app-level dependencies (global)
|
|
478
|
-
- Dependency overrides (testing)
|
|
479
|
-
- Async dependencies
|