跳到正文
DEV Community· RDJ·· 4 小時前AI 評分56

12 條 Cursor 規則避免 AI 助手寫出過時 FastAPI 程式碼

12 Cursor rules that stop AI assistants writing outdated FastAPI code

AI 導讀

作者分享 12 條 Cursor 專案規則,以 `.cursor/rules/` 中按檔案 glob 載入的 `.mdc` 檔,約束 AI 助手採用較新的 FastAPI 慣例。

正文

RDJ

AI coding assistants still reach for FastAPI patterns from a few years ago: .dict(), orm_mode, session.query(), HTTPException raised deep inside service code, SQLite in tests. The code runs, but it isn't the code you'd write today.

Cursor's project rules fix most of this. A rule is a small .mdc file in .cursor/rules/ with a glob, so it loads only when you edit matching files:

---
description: "FastAPI routers, dependencies and Pydantic v2 schemas"
globs: src/app/**/router.py,src/app/**/schemas.py,src/app/**/deps.py
alwaysApply: false
---
- One APIRouter(prefix="/<plural-resource>") per feature ...

These are the 12 conventions that made the biggest difference for me.

Routers and schemas

  1. Pydantic v2 APIs only. model_validate, model_dump, ConfigDict, field_validator. Never .dict(), parse_obj, orm_mode, class Config or the v1 validator decorator.
  2. Routers are thin and async. Parse, call a service, return a schema. No SQL or business rules in routers.
  3. Always declare response_model (or a return annotation) and an explicit status_code: 201 for create, 204 for delete.
  4. Schemas are named XCreate / XUpdate / XRead. Input models use ConfigDict(extra="forbid") so a sneaky "is_admin": true is rejected. Apply updates with model_dump(exclude_unset=True).

Database

  1. SQLAlchemy 2.0 style only. Mapped[...], mapped_column(), select(). Never session.query() or declarative_base().
  2. Services own the transaction with async with session.begin():. Repositories never commit. Use async_sessionmaker(expire_on_commit=False).
  3. Relationships default to lazy="raise". Load explicitly with selectinload() or joinedload(), so there's no hidden IO in async code.
  4. Set MetaData(naming_convention=...) on your Base so Alembic constraint names are deterministic. Never edit a migration that's already applied.

Errors, config and safety

  1. Services raise your own AppError subclasses, never HTTPException. One exception handler maps them to {"error": {"code": ..., "message": ...}}.
  2. Settings only through a cached get_settings() built on pydantic-settings. Never read os.environ elsewhere, and keep secrets as SecretStr.
  3. Never build SQL with f-strings. Use bound parameters or text(...).bindparams().

Tests

  1. pytest + pytest-asyncio + httpx.AsyncClient(transport=ASGITransport(app=app)), against a real Postgres with a rollback per test. Clear app.dependency_overrides after each test. No SQLite stand-in.

Using them

Drop rules like these into .cursor/rules/, one file per area, with globs that match your layout. For Claude Code, the same conventions work as a short CLAUDE.md at the repo root.


Disclosure: I made a FastAPI rules pack with these conventions written out as 7 scoped .mdc files plus a CLAUDE.md, and I sell it for $12 at codebaserules.com. Two of the files are a free download, no email needed. Everything above works without buying anything. I'd like to hear which of these you'd change.

來源:DEV Community · dev.to