codeforge-dev 1.4.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.
Files changed (131) hide show
  1. package/.devcontainer/.env +22 -0
  2. package/.devcontainer/CHANGELOG.md +197 -0
  3. package/.devcontainer/CLAUDE.md +117 -0
  4. package/.devcontainer/README.md +222 -0
  5. package/.devcontainer/config/main-system-prompt.md +502 -0
  6. package/.devcontainer/config/settings.json +47 -0
  7. package/.devcontainer/devcontainer.json +94 -0
  8. package/.devcontainer/features/README.md +113 -0
  9. package/.devcontainer/features/agent-browser/README.md +65 -0
  10. package/.devcontainer/features/agent-browser/devcontainer-feature.json +23 -0
  11. package/.devcontainer/features/agent-browser/install.sh +79 -0
  12. package/.devcontainer/features/ast-grep/README.md +24 -0
  13. package/.devcontainer/features/ast-grep/devcontainer-feature.json +24 -0
  14. package/.devcontainer/features/ast-grep/install.sh +51 -0
  15. package/.devcontainer/features/ccstatusline/README.md +296 -0
  16. package/.devcontainer/features/ccstatusline/devcontainer-feature.json +19 -0
  17. package/.devcontainer/features/ccstatusline/install.sh +290 -0
  18. package/.devcontainer/features/ccusage/README.md +205 -0
  19. package/.devcontainer/features/ccusage/devcontainer-feature.json +38 -0
  20. package/.devcontainer/features/ccusage/install.sh +132 -0
  21. package/.devcontainer/features/claude-code/README.md +498 -0
  22. package/.devcontainer/features/claude-code/config/settings.json +36 -0
  23. package/.devcontainer/features/claude-code/config/system-prompt.md +118 -0
  24. package/.devcontainer/features/claude-code/config/world-building-sp.md +1432 -0
  25. package/.devcontainer/features/claude-code/devcontainer-feature.json +42 -0
  26. package/.devcontainer/features/claude-code/install.sh +466 -0
  27. package/.devcontainer/features/claude-monitor/README.md +74 -0
  28. package/.devcontainer/features/claude-monitor/devcontainer-feature.json +38 -0
  29. package/.devcontainer/features/claude-monitor/install.sh +99 -0
  30. package/.devcontainer/features/lsp-servers/README.md +85 -0
  31. package/.devcontainer/features/lsp-servers/devcontainer-feature.json +40 -0
  32. package/.devcontainer/features/lsp-servers/install.sh +116 -0
  33. package/.devcontainer/features/mcp-qdrant/CHANGES.md +399 -0
  34. package/.devcontainer/features/mcp-qdrant/README.md +474 -0
  35. package/.devcontainer/features/mcp-qdrant/devcontainer-feature.json +57 -0
  36. package/.devcontainer/features/mcp-qdrant/install.sh +295 -0
  37. package/.devcontainer/features/mcp-qdrant/poststart-hook.sh +129 -0
  38. package/.devcontainer/features/mcp-reasoner/README.md +177 -0
  39. package/.devcontainer/features/mcp-reasoner/devcontainer-feature.json +20 -0
  40. package/.devcontainer/features/mcp-reasoner/install.sh +177 -0
  41. package/.devcontainer/features/mcp-reasoner/poststart-hook.sh +67 -0
  42. package/.devcontainer/features/notify-hook/README.md +86 -0
  43. package/.devcontainer/features/notify-hook/devcontainer-feature.json +23 -0
  44. package/.devcontainer/features/notify-hook/install.sh +38 -0
  45. package/.devcontainer/features/splitrail/README.md +140 -0
  46. package/.devcontainer/features/splitrail/devcontainer-feature.json +34 -0
  47. package/.devcontainer/features/splitrail/install.sh +129 -0
  48. package/.devcontainer/features/tree-sitter/README.md +138 -0
  49. package/.devcontainer/features/tree-sitter/devcontainer-feature.json +52 -0
  50. package/.devcontainer/features/tree-sitter/install.sh +173 -0
  51. package/.devcontainer/plugins/devs-marketplace/.claude-plugin/marketplace.json +106 -0
  52. package/.devcontainer/plugins/devs-marketplace/plugins/auto-formatter/.claude-plugin/plugin.json +7 -0
  53. package/.devcontainer/plugins/devs-marketplace/plugins/auto-formatter/hooks/hooks.json +17 -0
  54. package/.devcontainer/plugins/devs-marketplace/plugins/auto-formatter/scripts/format-file.py +101 -0
  55. package/.devcontainer/plugins/devs-marketplace/plugins/auto-linter/.claude-plugin/plugin.json +7 -0
  56. package/.devcontainer/plugins/devs-marketplace/plugins/auto-linter/hooks/hooks.json +17 -0
  57. package/.devcontainer/plugins/devs-marketplace/plugins/auto-linter/scripts/lint-file.py +137 -0
  58. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/.claude-plugin/plugin.json +8 -0
  59. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/claude-code-headless/SKILL.md +387 -0
  60. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/claude-code-headless/references/cli-flags-and-output.md +312 -0
  61. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/claude-code-headless/references/sdk-and-mcp.md +569 -0
  62. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/docker/SKILL.md +309 -0
  63. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/docker/references/compose-services.md +438 -0
  64. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/docker/references/dockerfile-patterns.md +340 -0
  65. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/docker-py/SKILL.md +412 -0
  66. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/docker-py/references/container-lifecycle.md +388 -0
  67. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/docker-py/references/resources-and-security.md +444 -0
  68. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/fastapi/SKILL.md +344 -0
  69. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/fastapi/references/middleware-and-lifespan.md +254 -0
  70. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/fastapi/references/pydantic-models.md +245 -0
  71. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/fastapi/references/routing-and-dependencies.md +255 -0
  72. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/fastapi/references/sse-and-streaming.md +318 -0
  73. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/pydantic-ai/SKILL.md +345 -0
  74. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/pydantic-ai/references/agents-and-tools.md +271 -0
  75. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/pydantic-ai/references/models-and-streaming.md +422 -0
  76. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/skill-building/SKILL.md +220 -0
  77. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/skill-building/references/cross-vendor-principles.md +139 -0
  78. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/skill-building/references/patterns-and-antipatterns.md +376 -0
  79. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/skill-building/references/skill-authoring-patterns.md +356 -0
  80. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/sqlite/SKILL.md +329 -0
  81. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/sqlite/references/advanced-queries.md +314 -0
  82. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/sqlite/references/javascript-patterns.md +323 -0
  83. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/sqlite/references/python-patterns.md +354 -0
  84. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/sqlite/references/schema-and-pragmas.md +326 -0
  85. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/svelte5/SKILL.md +356 -0
  86. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/svelte5/references/ai-sdk-svelte.md +128 -0
  87. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/svelte5/references/component-patterns.md +332 -0
  88. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/svelte5/references/layercake.md +203 -0
  89. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/svelte5/references/migration-guide.md +350 -0
  90. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/svelte5/references/runes-and-reactivity.md +328 -0
  91. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/svelte5/references/spa-and-routing.md +262 -0
  92. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/svelte5/references/svelte-dnd-action.md +181 -0
  93. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/testing/SKILL.md +414 -0
  94. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/testing/references/fastapi-testing.md +411 -0
  95. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/testing/references/svelte-testing.md +538 -0
  96. package/.devcontainer/plugins/devs-marketplace/plugins/codeforge-lsp/.claude-plugin/plugin.json +7 -0
  97. package/.devcontainer/plugins/devs-marketplace/plugins/dangerous-command-blocker/.claude-plugin/plugin.json +7 -0
  98. package/.devcontainer/plugins/devs-marketplace/plugins/dangerous-command-blocker/hooks/hooks.json +17 -0
  99. package/.devcontainer/plugins/devs-marketplace/plugins/dangerous-command-blocker/scripts/block-dangerous.py +110 -0
  100. package/.devcontainer/plugins/devs-marketplace/plugins/notify-hook/.claude-plugin/plugin.json +7 -0
  101. package/.devcontainer/plugins/devs-marketplace/plugins/notify-hook/hooks/hooks.json +17 -0
  102. package/.devcontainer/plugins/devs-marketplace/plugins/planning-reminder/.claude-plugin/plugin.json +7 -0
  103. package/.devcontainer/plugins/devs-marketplace/plugins/planning-reminder/hooks/hooks.json +17 -0
  104. package/.devcontainer/plugins/devs-marketplace/plugins/protected-files-guard/.claude-plugin/plugin.json +7 -0
  105. package/.devcontainer/plugins/devs-marketplace/plugins/protected-files-guard/hooks/hooks.json +17 -0
  106. package/.devcontainer/plugins/devs-marketplace/plugins/protected-files-guard/scripts/guard-protected.py +108 -0
  107. package/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/.claude-plugin/commands/ticket/357/200/272create-pr.md +337 -0
  108. package/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/.claude-plugin/commands/ticket/357/200/272new.md +166 -0
  109. package/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/.claude-plugin/commands/ticket/357/200/272review-commit.md +290 -0
  110. package/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/.claude-plugin/commands/ticket/357/200/272work.md +257 -0
  111. package/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/.claude-plugin/plugin.json +8 -0
  112. package/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/.claude-plugin/system-prompt.md +184 -0
  113. package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/.claude-plugin/plugin.json +6 -0
  114. package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/config/planning-instructions.md +14 -0
  115. package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/functional-conjuring-map.md +989 -0
  116. package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/hooks/hooks.json +33 -0
  117. package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/scripts/__pycache__/post-enhance-task.cpython-314.pyc +0 -0
  118. package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/scripts/enhance-planning.py +71 -0
  119. package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/scripts/enhancers/enhance-plan.sh +68 -0
  120. package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/scripts/enhancers/enhance-task.sh +120 -0
  121. package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/scripts/post-enhance-plan.py +133 -0
  122. package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/scripts/post-enhance-task.py +253 -0
  123. package/.devcontainer/scripts/setup-aliases.sh +80 -0
  124. package/.devcontainer/scripts/setup-config.sh +28 -0
  125. package/.devcontainer/scripts/setup-irie-claude.sh +32 -0
  126. package/.devcontainer/scripts/setup-plugins.sh +80 -0
  127. package/.devcontainer/scripts/setup.sh +58 -0
  128. package/LICENSE.txt +674 -0
  129. package/README.md +267 -0
  130. package/package.json +44 -0
  131. package/setup.js +83 -0
@@ -0,0 +1,245 @@
1
+ # Pydantic v2 Models -- Deep Dive
2
+
3
+ ## 1. Computed Fields
4
+
5
+ Computed fields are derived from other model fields at serialization time. They appear in JSON output but are not accepted in input:
6
+
7
+ ```python
8
+ from pydantic import BaseModel, computed_field
9
+
10
+ class Product(BaseModel):
11
+ price: float
12
+ tax_rate: float = 0.08
13
+
14
+ @computed_field
15
+ @property
16
+ def total(self) -> float:
17
+ return self.price * (1 + self.tax_rate)
18
+ ```
19
+
20
+ ```python
21
+ p = Product(price=100)
22
+ p.model_dump()
23
+ # {"price": 100.0, "tax_rate": 0.08, "total": 108.0}
24
+ ```
25
+
26
+ Computed fields participate in JSON Schema generation, appearing in OpenAPI docs with their return type.
27
+
28
+ ---
29
+
30
+ ## 2. Model Inheritance
31
+
32
+ ### Shared Base Models
33
+
34
+ Factor common fields into a base class. Input and output models inherit from the base and add their specific fields:
35
+
36
+ ```python
37
+ class UserBase(BaseModel):
38
+ email: str
39
+ display_name: str | None = None
40
+
41
+ class UserCreate(UserBase):
42
+ password: str
43
+
44
+ class UserUpdate(BaseModel):
45
+ email: str | None = None
46
+ display_name: str | None = None
47
+
48
+ class UserResponse(UserBase):
49
+ model_config = {"from_attributes": True}
50
+
51
+ id: int
52
+ created_at: datetime
53
+ ```
54
+
55
+ ### Partial Models for PATCH
56
+
57
+ Create update models where all fields are optional. This supports partial updates without requiring the client to send the full object:
58
+
59
+ ```python
60
+ from pydantic import BaseModel
61
+
62
+ class ItemBase(BaseModel):
63
+ name: str
64
+ description: str
65
+ price: float
66
+
67
+ class ItemUpdate(BaseModel):
68
+ name: str | None = None
69
+ description: str | None = None
70
+ price: float | None = None
71
+ ```
72
+
73
+ Use `model.model_dump(exclude_unset=True)` to get only the fields the client explicitly provided:
74
+
75
+ ```python
76
+ @router.patch("/{item_id}")
77
+ async def update_item(item_id: int, updates: ItemUpdate, db: DB):
78
+ update_data = updates.model_dump(exclude_unset=True)
79
+ await db.execute(
80
+ update(Item).where(Item.id == item_id).values(**update_data)
81
+ )
82
+ ```
83
+
84
+ ---
85
+
86
+ ## 3. Custom JSON Encoders
87
+
88
+ Pydantic v2 uses `model_serializer` and `field_serializer` for custom encoding:
89
+
90
+ ```python
91
+ from pydantic import BaseModel, field_serializer
92
+ from datetime import datetime
93
+
94
+ class Event(BaseModel):
95
+ name: str
96
+ timestamp: datetime
97
+
98
+ @field_serializer("timestamp")
99
+ def serialize_timestamp(self, dt: datetime, _info) -> str:
100
+ return dt.isoformat()
101
+ ```
102
+
103
+ For model-wide custom serialization:
104
+
105
+ ```python
106
+ from pydantic import model_serializer
107
+
108
+ class Point(BaseModel):
109
+ x: float
110
+ y: float
111
+
112
+ @model_serializer
113
+ def serialize_model(self) -> dict:
114
+ return {"coordinates": [self.x, self.y]}
115
+ ```
116
+
117
+ ---
118
+
119
+ ## 4. Discriminated Unions
120
+
121
+ Use a literal discriminator field to enable efficient parsing of polymorphic types. Pydantic checks the discriminator value first, then validates against the matching model:
122
+
123
+ ```python
124
+ from typing import Literal, Union, Annotated
125
+ from pydantic import BaseModel, Field
126
+
127
+ class TextBlock(BaseModel):
128
+ type: Literal["text"] = "text"
129
+ content: str
130
+
131
+ class ImageBlock(BaseModel):
132
+ type: Literal["image"] = "image"
133
+ url: str
134
+ alt_text: str | None = None
135
+
136
+ class CodeBlock(BaseModel):
137
+ type: Literal["code"] = "code"
138
+ language: str
139
+ source: str
140
+
141
+ Block = Annotated[
142
+ Union[TextBlock, ImageBlock, CodeBlock],
143
+ Field(discriminator="type"),
144
+ ]
145
+
146
+ class Document(BaseModel):
147
+ title: str
148
+ blocks: list[Block]
149
+ ```
150
+
151
+ Benefits of discriminated unions:
152
+ - Validation errors reference the specific model variant, not a generic union failure.
153
+ - Performance is constant-time (dict lookup by discriminator), not linear (try each variant).
154
+ - OpenAPI schema uses `oneOf` with `discriminator`, enabling typed client generation.
155
+
156
+ ---
157
+
158
+ ## 5. Validators and Constraints
159
+
160
+ ### Field-Level Validators
161
+
162
+ ```python
163
+ from pydantic import field_validator
164
+
165
+ class Registration(BaseModel):
166
+ username: str
167
+ age: int
168
+
169
+ @field_validator("username")
170
+ @classmethod
171
+ def username_alphanumeric(cls, v: str) -> str:
172
+ if not v.isalnum():
173
+ raise ValueError("must be alphanumeric")
174
+ return v
175
+
176
+ @field_validator("age")
177
+ @classmethod
178
+ def age_range(cls, v: int) -> int:
179
+ if v < 13 or v > 120:
180
+ raise ValueError("must be between 13 and 120")
181
+ return v
182
+ ```
183
+
184
+ ### Model-Level Validators
185
+
186
+ Validate relationships between fields using `model_validator`:
187
+
188
+ ```python
189
+ from pydantic import model_validator
190
+
191
+ class DateRange(BaseModel):
192
+ start: datetime
193
+ end: datetime
194
+
195
+ @model_validator(mode="after")
196
+ def validate_range(self) -> "DateRange":
197
+ if self.end <= self.start:
198
+ raise ValueError("end must be after start")
199
+ return self
200
+ ```
201
+
202
+ ### Field Constraints
203
+
204
+ ```python
205
+ from pydantic import Field
206
+
207
+ class Product(BaseModel):
208
+ name: str = Field(min_length=1, max_length=200)
209
+ price: float = Field(gt=0, description="Price in USD")
210
+ sku: str = Field(pattern=r"^[A-Z]{2}-\d{4}$")
211
+ tags: list[str] = Field(default_factory=list, max_length=10)
212
+ ```
213
+
214
+ ---
215
+
216
+ ## 6. BaseSettings for Configuration
217
+
218
+ `BaseSettings` reads values from environment variables, `.env` files, and constructor arguments with a defined priority:
219
+
220
+ ```python
221
+ from pydantic_settings import BaseSettings
222
+
223
+ class Settings(BaseSettings):
224
+ model_config = {"env_file": ".env", "env_prefix": "APP_"}
225
+
226
+ database_url: str
227
+ redis_url: str = "redis://localhost:6379"
228
+ debug: bool = False
229
+ allowed_origins: list[str] = ["http://localhost:3000"]
230
+ ```
231
+
232
+ ```python
233
+ # Usage in FastAPI
234
+ from functools import lru_cache
235
+
236
+ @lru_cache
237
+ def get_settings() -> Settings:
238
+ return Settings()
239
+
240
+ @app.get("/info")
241
+ async def info(settings: Settings = Depends(get_settings)):
242
+ return {"debug": settings.debug}
243
+ ```
244
+
245
+ Priority order (highest to lowest): constructor arguments, environment variables, `.env` file, field defaults. Use `lru_cache` to parse settings once rather than on every request.
@@ -0,0 +1,255 @@
1
+ # Routing and Dependencies -- Deep Dive
2
+
3
+ ## 1. APIRouter Organization
4
+
5
+ Structure routers by domain, one per module. Each router declares its own prefix, tags, and shared dependencies:
6
+
7
+ ```python
8
+ # app/routers/users.py
9
+ from fastapi import APIRouter, Depends
10
+ from app.dependencies import get_current_user
11
+
12
+ router = APIRouter(
13
+ prefix="/users",
14
+ tags=["users"],
15
+ dependencies=[Depends(get_current_user)],
16
+ )
17
+
18
+ @router.get("/me")
19
+ async def read_current_user(user: User = Depends(get_current_user)):
20
+ return user
21
+
22
+ @router.get("/{user_id}")
23
+ async def read_user(user_id: int):
24
+ return await fetch_user(user_id)
25
+ ```
26
+
27
+ ```python
28
+ # app/main.py
29
+ from fastapi import FastAPI
30
+ from app.routers import users, items, orders
31
+
32
+ app = FastAPI()
33
+ app.include_router(users.router)
34
+ app.include_router(items.router)
35
+ app.include_router(orders.router)
36
+ ```
37
+
38
+ ### Router-Level Dependencies
39
+
40
+ Dependencies declared at the router level apply to every endpoint in that router. This is ideal for authentication guards -- every endpoint in the router requires a valid user without repeating the dependency:
41
+
42
+ ```python
43
+ router = APIRouter(
44
+ prefix="/admin",
45
+ dependencies=[Depends(require_admin_role)],
46
+ )
47
+ ```
48
+
49
+ Override a router-level dependency at the endpoint level by re-declaring the same parameter type with a different `Depends()`:
50
+
51
+ ```python
52
+ @router.get("/public", dependencies=[])
53
+ async def public_endpoint():
54
+ return {"message": "no auth required"}
55
+ ```
56
+
57
+ ---
58
+
59
+ ## 2. Path Operation Configuration
60
+
61
+ ### Response Model Filtering
62
+
63
+ Use `response_model_exclude_unset` to omit fields the client did not send, useful for PATCH-style partial updates:
64
+
65
+ ```python
66
+ @router.patch("/{item_id}", response_model=ItemResponse)
67
+ async def update_item(
68
+ item_id: int,
69
+ updates: ItemUpdate,
70
+ response_model_exclude_unset=True,
71
+ ):
72
+ return await apply_updates(item_id, updates)
73
+ ```
74
+
75
+ ### Multiple Response Models
76
+
77
+ Declare alternative responses for documentation and client generation:
78
+
79
+ ```python
80
+ from fastapi import status
81
+
82
+ @router.post(
83
+ "/",
84
+ response_model=ItemResponse,
85
+ status_code=status.HTTP_201_CREATED,
86
+ responses={
87
+ 409: {"model": ErrorResponse, "description": "Item already exists"},
88
+ 422: {"model": ValidationErrorResponse},
89
+ },
90
+ )
91
+ async def create_item(item: ItemCreate):
92
+ ...
93
+ ```
94
+
95
+ ### Tags and Deprecation
96
+
97
+ ```python
98
+ @router.get("/legacy", deprecated=True, tags=["legacy"])
99
+ async def legacy_endpoint():
100
+ ...
101
+ ```
102
+
103
+ ---
104
+
105
+ ## 3. Nested and Overridden Dependencies
106
+
107
+ ### Nested Dependencies
108
+
109
+ Dependencies can depend on other dependencies. FastAPI resolves the full graph, caching each dependency once per request:
110
+
111
+ ```python
112
+ async def get_db():
113
+ db = SessionLocal()
114
+ try:
115
+ yield db
116
+ finally:
117
+ await db.close()
118
+
119
+ async def get_user_repo(db: AsyncSession = Depends(get_db)):
120
+ return UserRepository(db)
121
+
122
+ async def get_current_user(
123
+ token: str = Depends(oauth2_scheme),
124
+ repo: UserRepository = Depends(get_user_repo),
125
+ ):
126
+ user = await repo.find_by_token(token)
127
+ if not user:
128
+ raise HTTPException(status_code=401, detail="Invalid token")
129
+ return user
130
+ ```
131
+
132
+ The dependency graph resolves as: `oauth2_scheme` + `get_db` -> `get_user_repo` -> `get_current_user`. Each node executes once per request regardless of how many endpoints declare it.
133
+
134
+ ### Disabling Cache
135
+
136
+ Force a dependency to re-execute per injection point by setting `use_cache=False`:
137
+
138
+ ```python
139
+ async def get_timestamp():
140
+ return datetime.utcnow()
141
+
142
+ @router.get("/")
143
+ async def handler(
144
+ start: datetime = Depends(get_timestamp),
145
+ end: datetime = Depends(get_timestamp, use_cache=False),
146
+ ):
147
+ # start and end are different timestamps
148
+ ...
149
+ ```
150
+
151
+ ---
152
+
153
+ ## 4. WebSocket Endpoints
154
+
155
+ WebSocket routes use `@app.websocket()` and receive a `WebSocket` object for bidirectional communication:
156
+
157
+ ```python
158
+ from fastapi import WebSocket, WebSocketDisconnect
159
+
160
+ @app.websocket("/ws/{client_id}")
161
+ async def websocket_endpoint(websocket: WebSocket, client_id: str):
162
+ await websocket.accept()
163
+ try:
164
+ while True:
165
+ data = await websocket.receive_text()
166
+ await websocket.send_text(f"Echo: {data}")
167
+ except WebSocketDisconnect:
168
+ pass
169
+ ```
170
+
171
+ Dependencies work with WebSocket endpoints. Inject shared resources the same way as HTTP handlers:
172
+
173
+ ```python
174
+ @app.websocket("/ws")
175
+ async def ws_with_deps(websocket: WebSocket, db: DB):
176
+ await websocket.accept()
177
+ ...
178
+ ```
179
+
180
+ ### Connection Management
181
+
182
+ Track active connections for broadcasting:
183
+
184
+ ```python
185
+ class ConnectionManager:
186
+ def __init__(self):
187
+ self.active: list[WebSocket] = []
188
+
189
+ async def connect(self, ws: WebSocket):
190
+ await ws.accept()
191
+ self.active.append(ws)
192
+
193
+ def disconnect(self, ws: WebSocket):
194
+ self.active.remove(ws)
195
+
196
+ async def broadcast(self, message: str):
197
+ for ws in self.active:
198
+ await ws.send_text(message)
199
+
200
+ manager = ConnectionManager()
201
+ ```
202
+
203
+ ---
204
+
205
+ ## 5. Testing Endpoints
206
+
207
+ Use `httpx.AsyncClient` with FastAPI's built-in test support. Override dependencies to inject test doubles:
208
+
209
+ ```python
210
+ import pytest
211
+ from httpx import AsyncClient, ASGITransport
212
+ from app.main import app
213
+ from app.dependencies import get_db
214
+
215
+ async def mock_db():
216
+ yield FakeDatabase()
217
+
218
+ app.dependency_overrides[get_db] = mock_db
219
+
220
+ @pytest.fixture
221
+ async def client():
222
+ transport = ASGITransport(app=app)
223
+ async with AsyncClient(transport=transport, base_url="http://test") as ac:
224
+ yield ac
225
+
226
+ @pytest.mark.anyio
227
+ async def test_create_item(client: AsyncClient):
228
+ response = await client.post("/items/", json={"name": "Test", "price": 9.99})
229
+ assert response.status_code == 201
230
+ assert response.json()["name"] == "Test"
231
+ ```
232
+
233
+ ### Testing with Real Dependencies
234
+
235
+ For integration tests, use the actual dependency graph but point to a test database:
236
+
237
+ ```python
238
+ @pytest.fixture(autouse=True)
239
+ async def setup_test_db():
240
+ await create_test_tables()
241
+ yield
242
+ await drop_test_tables()
243
+ app.dependency_overrides.clear()
244
+ ```
245
+
246
+ ### Testing Authentication
247
+
248
+ Override the auth dependency to bypass token validation in tests:
249
+
250
+ ```python
251
+ async def mock_current_user():
252
+ return User(id=1, email="test@example.com", role="admin")
253
+
254
+ app.dependency_overrides[get_current_user] = mock_current_user
255
+ ```