mirror of
https://github.com/affaan-m/everything-claude-code.git
synced 2026-05-14 02:10:07 +08:00
docs: salvage FastAPI review patterns
This commit is contained in:
parent
1c06ad9524
commit
d52cdccb0d
@ -11,7 +11,7 @@
|
||||
{
|
||||
"name": "ecc",
|
||||
"source": "./",
|
||||
"description": "The most comprehensive Claude Code plugin — 50 agents, 188 skills, 68 legacy command shims, selective install profiles, and production-ready hooks for TDD, security scanning, code review, and continuous learning",
|
||||
"description": "The most comprehensive Claude Code plugin — 51 agents, 189 skills, 69 legacy command shims, selective install profiles, and production-ready hooks for TDD, security scanning, code review, and continuous learning",
|
||||
"version": "2.0.0-rc.1",
|
||||
"author": {
|
||||
"name": "Affaan Mustafa",
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "ecc",
|
||||
"version": "2.0.0-rc.1",
|
||||
"description": "Battle-tested Claude Code plugin for engineering teams — 50 agents, 188 skills, 68 legacy command shims, production-ready hooks, and selective install workflows evolved through continuous real-world use",
|
||||
"description": "Battle-tested Claude Code plugin for engineering teams — 51 agents, 189 skills, 69 legacy command shims, production-ready hooks, and selective install workflows evolved through continuous real-world use",
|
||||
"author": {
|
||||
"name": "Affaan Mustafa",
|
||||
"url": "https://x.com/affaanmustafa"
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
# Everything Claude Code (ECC) — Agent Instructions
|
||||
|
||||
This is a **production-ready AI coding plugin** providing 50 specialized agents, 188 skills, 68 commands, and automated hook workflows for software development.
|
||||
This is a **production-ready AI coding plugin** providing 51 specialized agents, 189 skills, 69 commands, and automated hook workflows for software development.
|
||||
|
||||
**Version:** 2.0.0-rc.1
|
||||
|
||||
@ -145,9 +145,9 @@ Troubleshoot failures: check test isolation → verify mocks → fix implementat
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
agents/ — 50 specialized subagents
|
||||
skills/ — 188 workflow skills and domain knowledge
|
||||
commands/ — 68 slash commands
|
||||
agents/ — 51 specialized subagents
|
||||
skills/ — 189 workflow skills and domain knowledge
|
||||
commands/ — 69 slash commands
|
||||
hooks/ — Trigger-based automations
|
||||
rules/ — Always-follow guidelines (common + per-language)
|
||||
scripts/ — Cross-platform Node.js utilities
|
||||
|
||||
16
README.md
16
README.md
@ -350,7 +350,7 @@ If you stacked methods, clean up in this order:
|
||||
/plugin list ecc@ecc
|
||||
```
|
||||
|
||||
**That's it!** You now have access to 50 agents, 188 skills, and 68 legacy command shims.
|
||||
**That's it!** You now have access to 51 agents, 189 skills, and 69 legacy command shims.
|
||||
|
||||
### Dashboard GUI
|
||||
|
||||
@ -448,7 +448,7 @@ everything-claude-code/
|
||||
| |-- plugin.json # Plugin metadata and component paths
|
||||
| |-- marketplace.json # Marketplace catalog for /plugin marketplace add
|
||||
|
|
||||
|-- agents/ # 50 specialized subagents for delegation
|
||||
|-- agents/ # 51 specialized subagents for delegation
|
||||
| |-- planner.md # Feature implementation planning
|
||||
| |-- architect.md # System design decisions
|
||||
| |-- tdd-guide.md # Test-driven development
|
||||
@ -1336,9 +1336,9 @@ The configuration is automatically detected from `.opencode/opencode.json`.
|
||||
|
||||
| Feature | Claude Code | OpenCode | Status |
|
||||
|---------|-------------|----------|--------|
|
||||
| Agents | PASS: 50 agents | PASS: 12 agents | **Claude Code leads** |
|
||||
| Commands | PASS: 68 commands | PASS: 31 commands | **Claude Code leads** |
|
||||
| Skills | PASS: 188 skills | PASS: 37 skills | **Claude Code leads** |
|
||||
| Agents | PASS: 51 agents | PASS: 12 agents | **Claude Code leads** |
|
||||
| Commands | PASS: 69 commands | PASS: 31 commands | **Claude Code leads** |
|
||||
| Skills | PASS: 189 skills | PASS: 37 skills | **Claude Code leads** |
|
||||
| Hooks | PASS: 8 event types | PASS: 11 events | **OpenCode has more!** |
|
||||
| Rules | PASS: 29 rules | PASS: 13 instructions | **Claude Code leads** |
|
||||
| MCP Servers | PASS: 14 servers | PASS: Full | **Full parity** |
|
||||
@ -1441,9 +1441,9 @@ ECC is the **first plugin to maximize every major AI coding tool**. Here's how e
|
||||
|
||||
| Feature | Claude Code | Cursor IDE | Codex CLI | OpenCode |
|
||||
|---------|------------|------------|-----------|----------|
|
||||
| **Agents** | 50 | Shared (AGENTS.md) | Shared (AGENTS.md) | 12 |
|
||||
| **Commands** | 68 | Shared | Instruction-based | 31 |
|
||||
| **Skills** | 188 | Shared | 10 (native format) | 37 |
|
||||
| **Agents** | 51 | Shared (AGENTS.md) | Shared (AGENTS.md) | 12 |
|
||||
| **Commands** | 69 | Shared | Instruction-based | 31 |
|
||||
| **Skills** | 189 | Shared | 10 (native format) | 37 |
|
||||
| **Hook Events** | 8 types | 15 types | None yet | 11 types |
|
||||
| **Hook Scripts** | 20+ scripts | 16 scripts (DRY adapter) | N/A | Plugin hooks |
|
||||
| **Rules** | 34 (common + lang) | 34 (YAML frontmatter) | Instruction-based | 13 instructions |
|
||||
|
||||
@ -160,7 +160,7 @@ Copy-Item -Recurse rules/typescript "$HOME/.claude/rules/"
|
||||
/plugin list ecc@ecc
|
||||
```
|
||||
|
||||
**完成!** 你现在可以使用 50 个代理、188 个技能和 68 个命令。
|
||||
**完成!** 你现在可以使用 51 个代理、189 个技能和 69 个命令。
|
||||
|
||||
### multi-* 命令需要额外配置
|
||||
|
||||
|
||||
@ -152,6 +152,7 @@ commands:
|
||||
- cpp-review
|
||||
- cpp-test
|
||||
- evolve
|
||||
- fastapi-review
|
||||
- feature-dev
|
||||
- flutter-build
|
||||
- flutter-review
|
||||
|
||||
70
agents/fastapi-reviewer.md
Normal file
70
agents/fastapi-reviewer.md
Normal file
@ -0,0 +1,70 @@
|
||||
---
|
||||
name: fastapi-reviewer
|
||||
description: Reviews FastAPI applications for async correctness, dependency injection, Pydantic schemas, security, OpenAPI quality, testing, and production readiness.
|
||||
tools: ["Read", "Grep", "Glob", "Bash"]
|
||||
model: sonnet
|
||||
---
|
||||
|
||||
You are a senior FastAPI reviewer focused on production Python APIs.
|
||||
|
||||
## Review Scope
|
||||
|
||||
- FastAPI app construction, routing, middleware, and exception handling.
|
||||
- Pydantic request, update, and response models.
|
||||
- Async database and HTTP patterns.
|
||||
- Dependency injection for database sessions, auth, pagination, and settings.
|
||||
- Authentication, authorization, CORS, rate limits, logging, and secret handling.
|
||||
- Test dependency overrides and client setup.
|
||||
- OpenAPI metadata and generated docs.
|
||||
|
||||
## Out of Scope
|
||||
|
||||
- Non-FastAPI frameworks unless they directly interact with the FastAPI app.
|
||||
- Broad Python style review already covered by `python-reviewer`.
|
||||
- Dependency additions without a concrete problem and maintenance rationale.
|
||||
|
||||
## Review Workflow
|
||||
|
||||
1. Locate the app entry point, usually `main.py`, `app.py`, or `app/main.py`.
|
||||
2. Identify routers, schemas, dependencies, database session setup, and tests.
|
||||
3. Run available local checks when safe, such as `pytest`, `ruff`, `mypy`, or `uv run pytest`.
|
||||
4. Review the changed files first, then inspect adjacent definitions needed to prove findings.
|
||||
5. Report only actionable issues with file and line references when available.
|
||||
|
||||
## Finding Priorities
|
||||
|
||||
### Critical
|
||||
|
||||
- Hardcoded secrets or tokens.
|
||||
- SQL built through string interpolation.
|
||||
- Passwords, token hashes, or internal auth fields exposed in response models.
|
||||
- Auth dependencies that can be bypassed or do not validate expiry/signature.
|
||||
|
||||
### High
|
||||
|
||||
- Blocking database or HTTP clients inside async routes.
|
||||
- Database sessions created inline in handlers instead of dependencies.
|
||||
- Test overrides targeting the wrong dependency.
|
||||
- `allow_origins=["*"]` combined with credentialed CORS.
|
||||
- Missing request validation for write endpoints.
|
||||
|
||||
### Medium
|
||||
|
||||
- Missing pagination on list endpoints.
|
||||
- OpenAPI docs missing response models or error response descriptions.
|
||||
- Duplicated route logic that should move into a service/dependency.
|
||||
- Missing timeout settings for external HTTP clients.
|
||||
|
||||
## Output Format
|
||||
|
||||
```text
|
||||
[SEVERITY] Short issue title
|
||||
File: path/to/file.py:42
|
||||
Issue: What is wrong and why it matters.
|
||||
Fix: Concrete change to make.
|
||||
```
|
||||
|
||||
End with:
|
||||
|
||||
- `Tests checked:` commands run or why they were skipped.
|
||||
- `Residual risk:` anything important that could not be verified.
|
||||
39
commands/fastapi-review.md
Normal file
39
commands/fastapi-review.md
Normal file
@ -0,0 +1,39 @@
|
||||
---
|
||||
description: Review a FastAPI application for architecture, async correctness, dependency injection, Pydantic schemas, security, performance, and testability.
|
||||
---
|
||||
|
||||
# FastAPI Review
|
||||
|
||||
Invoke the `fastapi-reviewer` agent for a focused FastAPI review.
|
||||
|
||||
## Usage
|
||||
|
||||
```text
|
||||
/fastapi-review [file-or-directory]
|
||||
```
|
||||
|
||||
## Review Areas
|
||||
|
||||
- App factory, router boundaries, middleware, and exception handlers.
|
||||
- Pydantic request and response schema separation.
|
||||
- Dependency injection for database sessions, auth, pagination, and settings.
|
||||
- Async database and external HTTP patterns.
|
||||
- CORS, auth, rate limits, logging, and secret handling.
|
||||
- OpenAPI metadata and documented response models.
|
||||
- Test client setup and dependency overrides.
|
||||
|
||||
## Expected Output
|
||||
|
||||
```text
|
||||
[SEVERITY] Short issue title
|
||||
File: path/to/file.py:42
|
||||
Issue: What is wrong and why it matters.
|
||||
Fix: Concrete change to make.
|
||||
```
|
||||
|
||||
## Related
|
||||
|
||||
- Agent: `fastapi-reviewer`
|
||||
- Skill: `fastapi-patterns`
|
||||
- Command: `/python-review`
|
||||
- Skill: `security-scan`
|
||||
@ -1,6 +1,6 @@
|
||||
# Everything Claude Code (ECC) — 智能体指令
|
||||
|
||||
这是一个**生产就绪的 AI 编码插件**,提供 50 个专业代理、188 项技能、68 条命令以及自动化钩子工作流,用于软件开发。
|
||||
这是一个**生产就绪的 AI 编码插件**,提供 51 个专业代理、189 项技能、69 条命令以及自动化钩子工作流,用于软件开发。
|
||||
|
||||
**版本:** 2.0.0-rc.1
|
||||
|
||||
@ -146,9 +146,9 @@
|
||||
## 项目结构
|
||||
|
||||
```
|
||||
agents/ — 50 个专业子代理
|
||||
skills/ — 188 个工作流技能和领域知识
|
||||
commands/ — 68 个斜杠命令
|
||||
agents/ — 51 个专业子代理
|
||||
skills/ — 189 个工作流技能和领域知识
|
||||
commands/ — 69 个斜杠命令
|
||||
hooks/ — 基于触发的自动化
|
||||
rules/ — 始终遵循的指导方针(通用 + 每种语言)
|
||||
scripts/ — 跨平台 Node.js 实用工具
|
||||
|
||||
@ -224,7 +224,7 @@ Copy-Item -Recurse rules/typescript "$HOME/.claude/rules/"
|
||||
/plugin list ecc@ecc
|
||||
```
|
||||
|
||||
**搞定!** 你现在可以使用 50 个智能体、188 项技能和 68 个命令了。
|
||||
**搞定!** 你现在可以使用 51 个智能体、189 项技能和 69 个命令了。
|
||||
|
||||
***
|
||||
|
||||
@ -1132,9 +1132,9 @@ opencode
|
||||
|
||||
| 功能特性 | Claude Code | OpenCode | 状态 |
|
||||
|---------|-------------|----------|--------|
|
||||
| 智能体 | PASS: 50 个 | PASS: 12 个 | **Claude Code 领先** |
|
||||
| 命令 | PASS: 68 个 | PASS: 31 个 | **Claude Code 领先** |
|
||||
| 技能 | PASS: 188 项 | PASS: 37 项 | **Claude Code 领先** |
|
||||
| 智能体 | PASS: 51 个 | PASS: 12 个 | **Claude Code 领先** |
|
||||
| 命令 | PASS: 69 个 | PASS: 31 个 | **Claude Code 领先** |
|
||||
| 技能 | PASS: 189 项 | PASS: 37 项 | **Claude Code 领先** |
|
||||
| 钩子 | PASS: 8 种事件类型 | PASS: 11 种事件 | **OpenCode 更多!** |
|
||||
| 规则 | PASS: 29 条 | PASS: 13 条指令 | **Claude Code 领先** |
|
||||
| MCP 服务器 | PASS: 14 个 | PASS: 完整 | **完全对等** |
|
||||
@ -1240,9 +1240,9 @@ ECC 是**第一个最大化利用每个主要 AI 编码工具的插件**。以
|
||||
|
||||
| 功能特性 | Claude Code | Cursor IDE | Codex CLI | OpenCode |
|
||||
|---------|------------|------------|-----------|----------|
|
||||
| **智能体** | 50 | 共享 (AGENTS.md) | 共享 (AGENTS.md) | 12 |
|
||||
| **命令** | 68 | 共享 | 基于指令 | 31 |
|
||||
| **技能** | 188 | 共享 | 10 (原生格式) | 37 |
|
||||
| **智能体** | 51 | 共享 (AGENTS.md) | 共享 (AGENTS.md) | 12 |
|
||||
| **命令** | 69 | 共享 | 基于指令 | 31 |
|
||||
| **技能** | 189 | 共享 | 10 (原生格式) | 37 |
|
||||
| **钩子事件** | 8 种类型 | 15 种类型 | 暂无 | 11 种类型 |
|
||||
| **钩子脚本** | 20+ 个脚本 | 16 个脚本 (DRY 适配器) | N/A | 插件钩子 |
|
||||
| **规则** | 34 (通用 + 语言) | 34 (YAML 前页) | 基于指令 | 13 条指令 |
|
||||
|
||||
@ -125,6 +125,7 @@
|
||||
"skills/django-tdd",
|
||||
"skills/django-verification",
|
||||
"skills/dotnet-patterns",
|
||||
"skills/fastapi-patterns",
|
||||
"skills/frontend-patterns",
|
||||
"skills/frontend-slides",
|
||||
"skills/golang-patterns",
|
||||
|
||||
@ -146,6 +146,7 @@
|
||||
"skills/evm-token-decimals/",
|
||||
"skills/exa-search/",
|
||||
"skills/fal-ai-media/",
|
||||
"skills/fastapi-patterns/",
|
||||
"skills/finance-billing-ops/",
|
||||
"skills/foundation-models-on-device/",
|
||||
"skills/frontend-patterns/",
|
||||
|
||||
58
rules/python/fastapi.md
Normal file
58
rules/python/fastapi.md
Normal file
@ -0,0 +1,58 @@
|
||||
---
|
||||
paths:
|
||||
- "**/app/**/*.py"
|
||||
- "**/fastapi/**/*.py"
|
||||
- "**/*_api.py"
|
||||
---
|
||||
# FastAPI Rules
|
||||
|
||||
Use these rules for FastAPI projects alongside the general Python rules.
|
||||
|
||||
## Structure
|
||||
|
||||
- Put app construction in `create_app()`.
|
||||
- Keep routers thin; move persistence and business behavior into services or CRUD helpers.
|
||||
- Keep request schemas, update schemas, and response schemas separate.
|
||||
- Keep database sessions and auth in dependencies.
|
||||
|
||||
## Async
|
||||
|
||||
- Use `async def` for endpoints that perform I/O.
|
||||
- Use async database and HTTP clients from async endpoints.
|
||||
- Do not call `requests`, sync SQLAlchemy sessions, or blocking file/network operations from async routes.
|
||||
|
||||
## Dependency Injection
|
||||
|
||||
```python
|
||||
@router.get("/users/{user_id}")
|
||||
async def get_user(
|
||||
user_id: str,
|
||||
db: AsyncSession = Depends(get_db),
|
||||
current_user: User = Depends(get_current_user),
|
||||
):
|
||||
...
|
||||
```
|
||||
|
||||
Do not create `SessionLocal()` or long-lived clients inside route handlers.
|
||||
|
||||
## Schemas
|
||||
|
||||
- Never include passwords, password hashes, access tokens, refresh tokens, or internal auth state in response models.
|
||||
- Use `response_model` on endpoints that return application data.
|
||||
- Use field constraints instead of hand-written validation when Pydantic can express the rule.
|
||||
|
||||
## Security
|
||||
|
||||
- Keep CORS origins environment-specific.
|
||||
- Do not combine wildcard origins with credentialed CORS.
|
||||
- Validate JWT expiry, issuer, audience, and algorithm.
|
||||
- Rate-limit auth and write-heavy endpoints.
|
||||
- Redact credentials, cookies, authorization headers, and tokens from logs.
|
||||
|
||||
## Testing
|
||||
|
||||
- Override the exact dependency used by `Depends`.
|
||||
- Clear `app.dependency_overrides` after tests.
|
||||
- Prefer async test clients for async applications.
|
||||
|
||||
See skill: `fastapi-patterns`.
|
||||
327
skills/fastapi-patterns/SKILL.md
Normal file
327
skills/fastapi-patterns/SKILL.md
Normal file
@ -0,0 +1,327 @@
|
||||
---
|
||||
name: fastapi-patterns
|
||||
description: FastAPI patterns for async APIs, dependency injection, Pydantic request and response models, OpenAPI docs, tests, security, and production readiness.
|
||||
origin: community
|
||||
---
|
||||
|
||||
# FastAPI Patterns
|
||||
|
||||
Production-oriented patterns for FastAPI services.
|
||||
|
||||
## When to Use
|
||||
|
||||
- Building or reviewing a FastAPI app.
|
||||
- Splitting routers, schemas, dependencies, and database access.
|
||||
- Writing async endpoints that call a database or external service.
|
||||
- Adding authentication, authorization, OpenAPI docs, tests, or deployment settings.
|
||||
- Checking a FastAPI PR for copy-pasteable examples and production risks.
|
||||
|
||||
## How It Works
|
||||
|
||||
Treat the FastAPI app as a thin HTTP layer over explicit dependencies and service code:
|
||||
|
||||
- `main.py` owns app construction, middleware, exception handlers, and router registration.
|
||||
- `schemas/` owns Pydantic request and response models.
|
||||
- `dependencies.py` owns database, auth, pagination, and request-scoped dependencies.
|
||||
- `services/` or `crud/` owns business and persistence operations.
|
||||
- `tests/` overrides dependencies instead of opening production resources.
|
||||
|
||||
Prefer small routers and explicit `response_model` declarations. Keep raw ORM objects, secrets, and framework globals out of response schemas.
|
||||
|
||||
## Project Layout
|
||||
|
||||
```text
|
||||
app/
|
||||
|-- main.py
|
||||
|-- config.py
|
||||
|-- dependencies.py
|
||||
|-- exceptions.py
|
||||
|-- api/
|
||||
| `-- routes/
|
||||
| |-- users.py
|
||||
| `-- health.py
|
||||
|-- core/
|
||||
| |-- security.py
|
||||
| `-- middleware.py
|
||||
|-- db/
|
||||
| |-- session.py
|
||||
| `-- crud.py
|
||||
|-- models/
|
||||
|-- schemas/
|
||||
`-- tests/
|
||||
```
|
||||
|
||||
## Application Factory
|
||||
|
||||
Use a factory so tests and workers can build the app with controlled settings.
|
||||
|
||||
```python
|
||||
from contextlib import asynccontextmanager
|
||||
|
||||
from fastapi import FastAPI
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
|
||||
from app.api.routes import health, users
|
||||
from app.config import settings
|
||||
from app.db.session import close_db, init_db
|
||||
from app.exceptions import register_exception_handlers
|
||||
|
||||
|
||||
@asynccontextmanager
|
||||
async def lifespan(app: FastAPI):
|
||||
await init_db()
|
||||
yield
|
||||
await close_db()
|
||||
|
||||
|
||||
def create_app() -> FastAPI:
|
||||
app = FastAPI(
|
||||
title=settings.api_title,
|
||||
version=settings.api_version,
|
||||
lifespan=lifespan,
|
||||
)
|
||||
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=settings.cors_origins,
|
||||
allow_credentials=bool(settings.cors_origins),
|
||||
allow_methods=["GET", "POST", "PUT", "PATCH", "DELETE"],
|
||||
allow_headers=["Authorization", "Content-Type"],
|
||||
)
|
||||
|
||||
register_exception_handlers(app)
|
||||
app.include_router(health.router, prefix="/health", tags=["health"])
|
||||
app.include_router(users.router, prefix="/api/v1/users", tags=["users"])
|
||||
return app
|
||||
|
||||
|
||||
app = create_app()
|
||||
```
|
||||
|
||||
Do not use `allow_origins=["*"]` with `allow_credentials=True`; browsers reject that combination and Starlette disallows it for credentialed requests.
|
||||
|
||||
## Pydantic Schemas
|
||||
|
||||
Keep request, update, and response models separate.
|
||||
|
||||
```python
|
||||
from datetime import datetime
|
||||
from typing import Annotated
|
||||
from uuid import UUID
|
||||
|
||||
from pydantic import BaseModel, ConfigDict, EmailStr, Field
|
||||
|
||||
|
||||
class UserBase(BaseModel):
|
||||
email: EmailStr
|
||||
full_name: Annotated[str, Field(min_length=1, max_length=100)]
|
||||
|
||||
|
||||
class UserCreate(UserBase):
|
||||
password: Annotated[str, Field(min_length=12, max_length=128)]
|
||||
|
||||
|
||||
class UserUpdate(BaseModel):
|
||||
email: EmailStr | None = None
|
||||
full_name: Annotated[str | None, Field(min_length=1, max_length=100)] = None
|
||||
|
||||
|
||||
class UserResponse(UserBase):
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
id: UUID
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
```
|
||||
|
||||
Response models must never include password hashes, access tokens, refresh tokens, or internal authorization state.
|
||||
|
||||
## Dependencies
|
||||
|
||||
Use dependency injection for request-scoped resources.
|
||||
|
||||
```python
|
||||
from collections.abc import AsyncIterator
|
||||
from uuid import UUID
|
||||
|
||||
from fastapi import Depends, HTTPException, status
|
||||
from fastapi.security import OAuth2PasswordBearer
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.core.security import decode_token
|
||||
from app.db.session import session_factory
|
||||
from app.models.user import User
|
||||
|
||||
|
||||
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/v1/auth/login")
|
||||
|
||||
|
||||
async def get_db() -> AsyncIterator[AsyncSession]:
|
||||
async with session_factory() as session:
|
||||
try:
|
||||
yield session
|
||||
await session.commit()
|
||||
except Exception:
|
||||
await session.rollback()
|
||||
raise
|
||||
|
||||
|
||||
async def get_current_user(
|
||||
token: str = Depends(oauth2_scheme),
|
||||
db: AsyncSession = Depends(get_db),
|
||||
) -> User:
|
||||
payload = decode_token(token)
|
||||
user_id = UUID(payload["sub"])
|
||||
user = await db.get(User, user_id)
|
||||
if user is None:
|
||||
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid token")
|
||||
return user
|
||||
```
|
||||
|
||||
Avoid creating sessions, clients, or credentials inline inside route handlers.
|
||||
|
||||
## Async Endpoints
|
||||
|
||||
Keep route handlers async when they perform I/O, and use async libraries inside them.
|
||||
|
||||
```python
|
||||
from fastapi import APIRouter, Depends, Query
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.dependencies import get_current_user, get_db
|
||||
from app.models.user import User
|
||||
from app.schemas.user import UserResponse
|
||||
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.get("/", response_model=list[UserResponse])
|
||||
async def list_users(
|
||||
limit: int = Query(default=50, ge=1, le=100),
|
||||
offset: int = Query(default=0, ge=0),
|
||||
db: AsyncSession = Depends(get_db),
|
||||
current_user: User = Depends(get_current_user),
|
||||
):
|
||||
result = await db.execute(
|
||||
select(User).order_by(User.created_at.desc()).limit(limit).offset(offset)
|
||||
)
|
||||
return result.scalars().all()
|
||||
```
|
||||
|
||||
Use `httpx.AsyncClient` for external HTTP calls from async handlers. Do not call `requests` in an async route.
|
||||
|
||||
## Error Handling
|
||||
|
||||
Centralize domain exceptions and keep response shapes stable.
|
||||
|
||||
```python
|
||||
from fastapi import FastAPI, Request
|
||||
from fastapi.responses import JSONResponse
|
||||
|
||||
|
||||
class ApiError(Exception):
|
||||
def __init__(self, status_code: int, code: str, message: str):
|
||||
self.status_code = status_code
|
||||
self.code = code
|
||||
self.message = message
|
||||
|
||||
|
||||
def register_exception_handlers(app: FastAPI) -> None:
|
||||
@app.exception_handler(ApiError)
|
||||
async def api_error_handler(request: Request, exc: ApiError):
|
||||
return JSONResponse(
|
||||
status_code=exc.status_code,
|
||||
content={"error": {"code": exc.code, "message": exc.message}},
|
||||
)
|
||||
```
|
||||
|
||||
## OpenAPI Customization
|
||||
|
||||
Assign the custom OpenAPI callable to `app.openapi`; do not just call the function once.
|
||||
|
||||
```python
|
||||
from fastapi import FastAPI
|
||||
from fastapi.openapi.utils import get_openapi
|
||||
|
||||
|
||||
def install_openapi(app: FastAPI) -> None:
|
||||
def custom_openapi():
|
||||
if app.openapi_schema:
|
||||
return app.openapi_schema
|
||||
app.openapi_schema = get_openapi(
|
||||
title="Service API",
|
||||
version="1.0.0",
|
||||
routes=app.routes,
|
||||
)
|
||||
return app.openapi_schema
|
||||
|
||||
app.openapi = custom_openapi
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
Override the dependency used by `Depends`, not an internal helper that route handlers never reference.
|
||||
|
||||
```python
|
||||
import pytest
|
||||
from httpx import ASGITransport, AsyncClient
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.dependencies import get_db
|
||||
from app.main import create_app
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
async def client(test_session: AsyncSession):
|
||||
app = create_app()
|
||||
|
||||
async def override_get_db():
|
||||
yield test_session
|
||||
|
||||
app.dependency_overrides[get_db] = override_get_db
|
||||
async with AsyncClient(
|
||||
transport=ASGITransport(app=app),
|
||||
base_url="http://test",
|
||||
) as test_client:
|
||||
yield test_client
|
||||
app.dependency_overrides.clear()
|
||||
```
|
||||
|
||||
## Security Checklist
|
||||
|
||||
- Hash passwords with `argon2-cffi`, `bcrypt`, or a current passlib-compatible hasher.
|
||||
- Validate JWT issuer, audience, expiry, and signing algorithm.
|
||||
- Keep CORS origins environment-specific.
|
||||
- Put rate limits on auth and write-heavy endpoints.
|
||||
- Use Pydantic models for all request bodies.
|
||||
- Use ORM parameter binding or SQLAlchemy Core expressions; never build SQL with f-strings.
|
||||
- Redact tokens, authorization headers, cookies, and passwords from logs.
|
||||
- Run dependency audit tooling in CI.
|
||||
|
||||
## Performance Checklist
|
||||
|
||||
- Configure database connection pooling explicitly.
|
||||
- Add pagination to list endpoints.
|
||||
- Watch for N+1 queries and use eager loading intentionally.
|
||||
- Use async HTTP/database clients in async paths.
|
||||
- Add compression only after checking payload size and CPU tradeoffs.
|
||||
- Cache stable expensive reads behind explicit invalidation.
|
||||
|
||||
## Examples
|
||||
|
||||
Use these examples as patterns, not as project-wide templates:
|
||||
|
||||
- Application factory: configure middleware and routers once in `create_app`.
|
||||
- Schema split: `UserCreate`, `UserUpdate`, and `UserResponse` have different responsibilities.
|
||||
- Dependency override: tests override `get_db` directly.
|
||||
- OpenAPI customization: assign `app.openapi = custom_openapi`.
|
||||
|
||||
## See Also
|
||||
|
||||
- Agent: `fastapi-reviewer`
|
||||
- Command: `/fastapi-review`
|
||||
- Skill: `python-patterns`
|
||||
- Skill: `python-testing`
|
||||
- Skill: `api-design`
|
||||
Loading…
x
Reference in New Issue
Block a user