Battle-tested Claude Code prompts for FastAPI routes, Pydantic v2 models, dependency injection, and async SQLAlchemy. Copy, fill brackets, paste.
FastAPI gives Claude Code a lot to work with: explicit types, dependency injection, and clear separation of routes/schemas/services. Used right, Claude can produce production-quality endpoints in one pass. The prompts below match the patterns most teams already use.
Add a 'projects' resource to the API. Conventions in this repo:
- routes/projects.py (APIRouter, prefix='/projects', tags=['projects'])
- schemas/projects.py (ProjectCreate, ProjectUpdate, ProjectRead — Pydantic v2)
- services/projects.py (async functions, take AsyncSession, return ORM or None)
- models/project.py (SQLAlchemy 2.0 declarative, Mapped[...])
Read routes/users.py and services/users.py FIRST as the template.
Endpoints needed:
- POST /projects (201, body ProjectCreate, returns ProjectRead)
- GET /projects (paginated, ?limit=50&cursor=...)
- GET /projects/{id} (404 if not owned by current user)
- PATCH /projects/{id} (ProjectUpdate — partial)
- DELETE /projects/{id} (204, soft delete via deleted_at)
Constraints:
- All endpoints async def
- Use the existing get_current_user and get_async_session deps
- Reuse the cursor pagination helper from common/pagination.py
- Do NOT add a service if a one-line ORM call suffices — match users.py density
- Generate an Alembic migration in the same diff
I'll review before you write tests.
Generate a Pydantic v2 model for this Stripe webhook payload:
[PASTE JSON]
Rules:
- Use Annotated[X, Field(...)] for any constrained field
- snake_case Python names, alias them to the JSON keys (use populate_by_name)
- ConfigDict(extra='forbid') — we want a hard fail on unknown fields so Stripe API
changes surface in CI, not silently
- Discriminate union types on 'type' field if multiple event shapes are present
- Place in schemas/stripe_events.py — match the import block of schemas/billing.py
- Add a docstring on each top-level class with the Stripe event names it represents
GET /search?q=... is slow (p95 = 1.4s, target 200ms). Read routes/search.py and
services/search.py. Identify the bottleneck.
Do not propose changes yet. First produce a 5-line analysis:
- Suspected root cause (1 line)
- Where (file:line)
- Evidence in the code (1-2 lines)
- Cheapest fix (1 line)
- What would NOT help (so I don't go down those paths)
Common causes worth checking:
- N+1 from lazy SQLAlchemy relationships
- Missing index on the search column
- Sync I/O inside an async endpoint (run_in_threadpool missing)
- Pagination with OFFSET on a large table (use cursor instead)
- Pydantic re-serializing huge nested objects
## FastAPI conventions
- Python 3.12, Pydantic v2, SQLAlchemy 2.0 async, Alembic for migrations
- All endpoints async def. Block I/O wrapped in run_in_threadpool.
- Routes ≤ 25 lines. Business logic in services/.py.
- Schemas in schemas/.py — never inline in routes.
- Auth dep: get_current_user. Session dep: get_async_session.
- Errors: raise HTTPException(status_code=..., detail=...). Never return dicts with error.
- Tests: pytest + httpx.AsyncClient. Fixtures in tests/conftest.py.
Related: calling Claude API from FastAPI, testing prompts.