Back to list
physics91

fastapi-reviewer

by physics91

Claude Code hooks를 활용하여 세션 컴팩션 시 AGENTS.md 컨텍스트를 자동으로 보존/복원하는 플러그인

0🍴 0📅 Dec 29, 2025

SKILL.md


name: fastapi-reviewer description: | WHEN: FastAPI project review, Pydantic models, async endpoints, dependency injection WHAT: Pydantic validation + Dependency injection + Async patterns + OpenAPI docs + Security WHEN NOT: Django → django-reviewer, Flask → flask-reviewer, General Python → python-reviewer

FastAPI Reviewer Skill

Purpose

Reviews FastAPI projects for API design, Pydantic usage, async patterns, and security.

When to Use

  • FastAPI project code review
  • Pydantic model review
  • API endpoint design review
  • Async/await pattern check
  • Dependency injection review

Project Detection

  • fastapi in requirements.txt/pyproject.toml
  • from fastapi import imports
  • main.py with FastAPI() app
  • routers/ directory structure

Workflow

Step 1: Analyze Project

**FastAPI**: 0.100+
**Pydantic**: v2
**Database**: SQLAlchemy/Tortoise/Prisma
**Auth**: OAuth2/JWT
**Docs**: OpenAPI auto-generated

Step 2: Select Review Areas

AskUserQuestion:

"Which areas to review?"
Options:
- Full FastAPI review (recommended)
- Pydantic models and validation
- Dependency injection patterns
- Async/await usage
- Security and authentication
multiSelect: true

Detection Rules

Pydantic Models

CheckRecommendationSeverity
dict instead of modelUse Pydantic BaseModelMEDIUM
Missing Field validationAdd Field constraintsMEDIUM
No Config classAdd model_configLOW
Mutable default in FieldUse default_factoryHIGH
# BAD: Plain dict response
@app.get("/user")
async def get_user() -> dict:
    return {"name": "John", "age": 30}

# GOOD: Pydantic model
class UserResponse(BaseModel):
    name: str = Field(..., min_length=1, max_length=100)
    age: int = Field(..., ge=0, le=150)

    model_config = ConfigDict(from_attributes=True)

@app.get("/user")
async def get_user() -> UserResponse:
    return UserResponse(name="John", age=30)

# BAD: Mutable default
class Config(BaseModel):
    items: list[str] = []  # Shared across instances!

# GOOD: default_factory
class Config(BaseModel):
    items: list[str] = Field(default_factory=list)

Dependency Injection

CheckRecommendationSeverity
Repeated code in endpointsExtract to Depends()MEDIUM
Global state accessUse dependency injectionHIGH
No cleanup in depsUse yield for cleanupMEDIUM
Hardcoded dependenciesUse Depends for testabilityMEDIUM
# BAD: Repeated DB session code
@app.get("/users")
async def get_users():
    db = SessionLocal()
    try:
        return db.query(User).all()
    finally:
        db.close()

# GOOD: Dependency injection
async def get_db() -> AsyncGenerator[AsyncSession, None]:
    async with async_session() as session:
        yield session

@app.get("/users")
async def get_users(db: AsyncSession = Depends(get_db)):
    result = await db.execute(select(User))
    return result.scalars().all()

Async Patterns

CheckRecommendationSeverity
sync def for I/OUse async defHIGH
Blocking call in asyncUse run_in_executorCRITICAL
No async DB driverUse asyncpg/aiosqliteHIGH
sync file I/OUse aiofilesMEDIUM
# BAD: Blocking call in async
@app.get("/data")
async def get_data():
    response = requests.get(url)  # Blocks event loop!
    return response.json()

# GOOD: Async HTTP client
@app.get("/data")
async def get_data():
    async with httpx.AsyncClient() as client:
        response = await client.get(url)
        return response.json()

# BAD: Sync file read
@app.get("/file")
async def read_file():
    with open("data.txt") as f:
        return f.read()

# GOOD: Async file read
@app.get("/file")
async def read_file():
    async with aiofiles.open("data.txt") as f:
        return await f.read()

API Design

CheckRecommendationSeverity
No response_modelAdd response_model paramMEDIUM
Missing status codesAdd responses paramLOW
No tagsAdd tags for groupingLOW
Inconsistent namingUse RESTful conventionsMEDIUM
# BAD: Minimal endpoint
@app.post("/user")
async def create(data: dict):
    return {"id": 1}

# GOOD: Full specification
@app.post(
    "/users",
    response_model=UserResponse,
    status_code=status.HTTP_201_CREATED,
    responses={
        409: {"model": ErrorResponse, "description": "User exists"},
    },
    tags=["users"],
    summary="Create a new user",
)
async def create_user(
    user: UserCreate,
    db: AsyncSession = Depends(get_db),
) -> UserResponse:
    """Create a new user with the provided details."""
    return await user_service.create(db, user)

Security

CheckRecommendationSeverity
No auth on endpointsAdd Depends(get_current_user)CRITICAL
Secrets in codeUse environment variablesCRITICAL
No rate limitingAdd slowapi/fastapi-limiterHIGH
Missing CORS configConfigure CORSMiddlewareHIGH
# Security setup
from fastapi.security import OAuth2PasswordBearer
from fastapi.middleware.cors import CORSMiddleware

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

async def get_current_user(
    token: str = Depends(oauth2_scheme),
    db: AsyncSession = Depends(get_db),
) -> User:
    user = await verify_token(token, db)
    if not user:
        raise HTTPException(status_code=401, detail="Invalid token")
    return user

# Protected endpoint
@app.get("/me")
async def get_me(user: User = Depends(get_current_user)):
    return user

Response Template

## FastAPI Code Review Results

**Project**: [name]
**FastAPI**: 0.109 | **Pydantic**: v2 | **DB**: SQLAlchemy async

### Pydantic Models
| Status | File | Issue |
|--------|------|-------|
| HIGH | schemas.py:15 | Mutable default in Field |

### Dependency Injection
| Status | File | Issue |
|--------|------|-------|
| MEDIUM | routers/users.py | Repeated DB session code |

### Async Patterns
| Status | File | Issue |
|--------|------|-------|
| CRITICAL | services/external.py:34 | Blocking requests.get() call |

### Security
| Status | File | Issue |
|--------|------|-------|
| CRITICAL | main.py | No CORS configuration |

### Recommended Actions
1. [ ] Replace blocking HTTP calls with httpx async
2. [ ] Add CORS middleware configuration
3. [ ] Extract repeated code to dependencies
4. [ ] Add response_model to all endpoints

Best Practices

  1. Pydantic v2: Use model_config, Field validators
  2. Async Everything: DB, HTTP, file I/O
  3. Dependencies: Extract common logic
  4. Security: OAuth2, CORS, rate limiting
  5. Documentation: OpenAPI auto-docs with examples

Integration

  • python-reviewer: General Python patterns
  • security-scanner: API security audit
  • api-documenter: OpenAPI enhancement

Score

Total Score

50/100

Based on repository quality metrics

SKILL.md

SKILL.mdファイルが含まれている

+20
LICENSE

ライセンスが設定されている

0/10
説明文

100文字以上の説明がある

0/10
人気

GitHub Stars 100以上

0/15
最近の活動

3ヶ月以内に更新がある

0/10
フォーク

10回以上フォークされている

0/5
Issue管理

オープンIssueが50未満

+5
言語

プログラミング言語が設定されている

+5
タグ

1つ以上のタグが設定されている

0/5

Reviews

💬

Reviews coming soon