Comprehensive Rules for designing, implementing, and maintaining high-quality REST/GraphQL APIs with TypeScript (NestJS) and Python (FastAPI).
You know the pain: APIs that work in development but fail in production. Inconsistent error handling across endpoints. Security vulnerabilities discovered after deployment. Documentation that's perpetually out of sync. Endless back-and-forth with frontend teams because your API responses aren't predictable.
These aren't just development friction points—they're productivity killers that compound over time.
This comprehensive ruleset eliminates the guesswork from API development by enforcing production-ready patterns directly in your editor. Instead of remembering dozens of best practices across TypeScript/NestJS and Python/FastAPI, you get intelligent code completion that guides you toward secure, scalable API patterns.
Key problems solved:
src/modules/<feature>/{controllers,services,dto})Before: 30 minutes of setup time
After: 3 minutes with Cursor Rules
// Auto-completed with proper patterns
@Get(':id')
@UseGuards(JwtAuthGuard)
@ApiResponse({ status: 200, type: UserDto })
async findOne(@Param('id', ParseUUIDPipe) id: string): Promise<UserDto> {
const user = await this.userService.find(id);
if (!user) throw new NotFoundException(`User ${id} not found`);
return user; // happy path last
}
Before: Different error formats across endpoints
// Inconsistent error handling
throw new Error('Something went wrong');
return { error: 'User not found' };
throw new HttpException('Bad request', 400);
After: Standardized error envelope
// Auto-generated standardized format
throw new NotFoundException(`User ${id} not found`);
// Results in: { "error": { "code": "USER_NOT_FOUND", "message": "User 42 not found", "docs": "https://api.example.com/errors#USER_NOT_FOUND" } }
Before: Manual setup for each route
@app.post("/users/")
def create_user(user_data: dict):
# Manual validation
# No automatic docs
# Inconsistent error handling
return {"id": 1, "name": user_data["name"]}
After: Production-ready patterns
@router.post("/users/", status_code=201, response_model=UserResponse)
async def create_user(
user_data: UserCreate,
db: Session = Depends(get_db)
) -> UserResponse:
# Automatic validation, docs, and error handling
return await user_service.create(db, user_data)
.cursorrules fileThe rules automatically guide you toward this proven structure:
src/
modules/
users/
controllers/user.controller.ts
services/user.service.ts
dto/user.dto.ts
entities/user.entity.ts
orders/
...
For NestJS projects, the rules prompt you to set up:
app.useGlobalPipes(new ValidationPipe({
whitelist: true,
forbidNonWhitelisted: true
}));
The rules automatically configure OpenAPI generation:
/docs/swaggerThese rules don't just provide code snippets—they encode years of production API development experience into patterns that guide your decision-making. You'll spend less time debugging authentication issues, more time building features that matter.
The ruleset enforces the Richardson Maturity Model Level 2+, implements proper HTTP semantics, and includes observability patterns that make your APIs production-ready from day one.
Your APIs will be more secure, performant, and maintainable than 90% of production APIs currently running.
Ready to transform how you build APIs? Install these Cursor Rules and experience the difference in your next endpoint implementation.
You are an expert in API Design, TypeScript, Python, NestJS, FastAPI, GraphQL, OpenAPI.
Key Principles
- Design for humans first: intuitive resource-oriented URIs, clear verbs, and predictable behavior.
- Follow the Richardson Maturity Model level 2+ (proper HTTP verbs & status codes).
- Keep APIs stateless and idempotent where possible.
- Version everything (URI or Header) and never break an existing contract.
- Prefer descriptive errors over generic 500s; document every error object.
- Automate: generate OpenAPI/Swagger docs directly from source; CI must fail on spec drift.
- Security is non-negotiable: enforce TLS, OAuth 2.0/JWT, and rate-limit all public endpoints.
- Write extensive tests (unit, contract, integration, e2e) before deployment.
- Build for observability: structured logging, tracing IDs, and metrics on every request.
TypeScript (NestJS)
- Use `class-validator` DTOs; annotate all properties (`@IsString()`, `@IsUUID()`).
- Always return typed responses with `@ApiResponse` decorators for Swagger.
- Controllers only orchestrate; business logic lives in Services.
- Prefer Enumerations for finite sets (e.g., enum OrderStatus).
- Use `readonly` and `private` modifiers; no public mutable state.
- Naming:
• File: kebab-case (`user.controller.ts`, `order.service.ts`).
• Class: PascalCase (`UserController`).
- Exception filters: extend `HttpException` and register globally; never throw raw errors.
- Enable strict compilation flags: `"strict": true`, `"noImplicitAny": true`.
- Example (happy-path last):
```ts
@Get(':id')
async findOne(@Param('id', ParseUUIDPipe) id: string): Promise<UserDto> {
const user = await this.userService.find(id);
if (!user) throw new NotFoundException(`User ${id} not found`);
return user; // happy path
}
```
Python (FastAPI)
- Use Pydantic models for all in/out schemas; enable `orm_mode`.
- Async everywhere (`async def`) to leverage uvicorn workers.
- Dependency injection: use `Depends` for auth, DB sessions, pagination.
- Route naming: kebab-case (`/users/{user_id}/orders`).
- Group routers by resource (`users.py`, `orders.py`) and include with tags.
- Annotate status codes: `@router.post(..., status_code=201)`. Avoid implicit 200.
- Example error model:
```py
class APIError(BaseModel):
code: str
message: str
docs: HttpUrl
```
- Raise `HTTPException(status_code=404, detail="Product not found", headers={"X-Error": "NF-01"})`.
Error Handling and Validation
- Validate request body, params, and headers before hitting business logic.
- Return standardized error envelope:
```json
{ "error": { "code": "USER_NOT_FOUND", "message": "User 42 not found", "docs": "https://api.example.com/errors#USER_NOT_FOUND" } }
```
- Map common errors:
• 400 – validation failed
• 401 – unauthenticated
• 403 – unauthorized
• 404 – not found
• 409 – conflict (duplicate)
• 429 – too many requests (include `Retry-After`)
- Log stack traces server-side only; never expose internals to clients.
- Use circuit breakers and retries on upstream failures; surface 502/504 gracefully.
Framework-Specific Rules
NestJS
- Structure: `src/modules/<feature>/{controllers,services,dto,entities}`.
- Global pipes: `ValidationPipe({ whitelist: true, forbidNonWhitelisted: true })`.
- Versioning: `app.enableVersioning({ type: VersioningType.URI })`; deprecate with `@ApiDeprecated`.
- Auth guard: implement `JwtAuthGuard` and apply with `@UseGuards`.
FastAPI
- Mount versions: `app = FastAPI(root_path="/v1")`; keep v1 router frozen after release.
- Add `@api_route` wrappers to auto-tag and auto-version.
- Integrate `fastapi-pagination` for easy cursor/offset pagination.
- Serve static OpenAPI JSON at `/openapi.json`; freeze hash in CI to detect drift.
GraphQL APIs
- Keep mutations side-effectful, queries pure; follow Relay spec for connections.
- Use DataLoader to batch N+1 queries.
- Version via schema directives (`@deprecated(reason: "Use newField")`).
- Enforce depth & complexity limits on server.
Additional Sections
Testing
- Unit: services & utilities (≥90% coverage).
- Contract: use `pact` files; fail CI on breaking change.
- Integration: spin up ephemeral DB with Docker Compose.
- Load: run k6 scripts; SLO: P95 < 150 ms.
Performance
- Implement caching layers:
• In-memory (LRU) for config/meta.
• Redis for user-scoped data (TTL <= 5 min).
- Use ETags and `If-None-Match` for GET caching.
- Paginate lists (>100 items) with limit/offset or cursor.
- Asynchronous background jobs via BullMQ (NestJS) or Celery (FastAPI).
Security
- Enforce HTTPS; redirect plain HTTP.
- OAuth 2.0 + JWT; rotate signing keys; use short-lived access tokens (≤15 min).
- Rate limit (100 req/min/IP) with Redis store; respond `429` when exceeded.
- Add `Content-Security-Policy`, `X-Content-Type-Options`, `X-Frame-Options` headers.
- Sanitize inputs to avoid SQL/NoSQL injection; use prepared statements/ORM.
Documentation
- Auto-generate OpenAPI; host Swagger UI at `/docs` (NestJS) or `/swagger` (FastAPI).
- Each endpoint must include: summary, request/response schema, example, auth scope.
- Keep changelog (`CHANGELOG.md`) aligned with semantic versioning.
Release & Versioning
- Semantic versioning (MAJOR.MINOR.PATCH).
- Deprecate old versions after 12 months; notify consumers 90 days before removal.
- Use blue/green deployments; never down APIs during rollout.
Observability
- Correlate logs with `X-Request-ID` header; propagate across microservices.
- Export metrics: latency, TPS, error rate to Prometheus.
- Trace with OpenTelemetry; instrument middleware and DB calls.
Coding Style Recap
- Early return for errors; happy path at bottom.
- One responsibility per function; max 50 LOC.
- Self-explanatory names: `getUserOrders`, `updateProductStock`.
- No magic numbers; use constants/enums.
- Keep controllers thin, services thick.
Use these rules to craft robust, secure, and maintainable APIs that delight developers and scale with demand.