Use this template when generating backend API endpoints with AI assistance.
Stack:
- Runtime: Node.js 20.x
- Framework: Express.js 4.18+ / Fastify 4.x / Nest.js 10.x
- Language: TypeScript 5.x
- Database: PostgreSQL 15+ / MongoDB 6.x
- ORM: Prisma 5.x / TypeORM 0.3.x
- Validation: Zod 3.x
- Authentication: JWT (jsonwebtoken 9.x)
Existing Code:
- User authentication system implemented
- Database connection established
- Middleware: auth, error handling, logging
- Base repository pattern for data access
Conventions:
- Async/await (no callbacks)
- Result<T, E> return types for error handling
- Dependency injection pattern
- Feature-based folder structure
- 90%+ test coverage required
Create a REST API endpoint for [DESCRIBE FEATURE]
- [Requirement 1]
- [Requirement 2]
- [Requirement 3]
METHOD /api/v1/resource
Headers:
{
"Authorization": "Bearer {jwt_token}",
"Content-Type": "application/json"
}Body:
{
"field1": "string",
"field2": "number",
"field3": "boolean"
}Success (200/201):
{
"success": true,
"data": {
"id": "uuid",
"field1": "value",
"createdAt": "2025-10-15T10:30:00Z"
}
}Validation Error (400):
{
"success": false,
"error": "Validation failed",
"fields": {
"field1": "Error message",
"field2": "Error message"
}
}Unauthorized (401):
{
"success": false,
"error": "Unauthorized"
}Not Found (404):
{
"success": false,
"error": "Resource not found"
}Server Error (500):
{
"success": false,
"error": "Internal server error"
}Use Zod schema:
const schema = z.object({
field1: z.string()
.min(2, "Minimum 2 characters")
.max(100, "Maximum 100 characters")
.trim(),
field2: z.number()
.int("Must be integer")
.positive("Must be positive")
.min(1)
.max(1000),
field3: z.boolean(),
email: z.string().email("Invalid email").max(255),
// Optional field
field4: z.string().optional(),
// Enum
status: z.enum(['active', 'inactive', 'pending']),
// Array
tags: z.array(z.string()).min(1).max(10),
});src/features/[feature-name]/
├── [feature].controller.ts # HTTP handling
├── [feature].service.ts # Business logic
├── [feature].repository.ts # Data access
├── [feature].types.ts # TypeScript types
├── [feature].validator.ts # Zod schemas
└── __tests__/
├── [feature].controller.test.ts
├── [feature].service.test.ts
└── [feature].repository.test.ts
Controller:
import { Request, Response } from 'express';
import { UserService } from './user.service';
import { createUserSchema } from './user.validator';
export class UserController {
constructor(private userService: UserService) {}
async create(req: Request, res: Response): Promise<void> {
// Validate
const validation = createUserSchema.safeParse(req.body);
if (!validation.success) {
res.status(400).json({
success: false,
error: 'Validation failed',
fields: validation.error.flatten().fieldErrors,
});
return;
}
// Business logic
const result = await this.userService.create(validation.data);
if (!result.success) {
res.status(500).json({
success: false,
error: result.error.message,
});
return;
}
res.status(201).json({
success: true,
data: result.data,
});
}
}Service:
import { UserRepository } from './user.repository';
import { CreateUserDTO, User } from './user.types';
import { Result } from '@/utils/result';
export class UserService {
constructor(private repository: UserRepository) {}
async create(data: CreateUserDTO): Promise<Result<User, Error>> {
try {
// Business logic
const user = await this.repository.create(data);
return { success: true, data: user };
} catch (error) {
return { success: false, error: error as Error };
}
}
}CRITICAL - Never Skip:
-
Input Validation
- Validate ALL inputs with Zod schema
- Sanitize strings (trim, escape)
- Limit array/string sizes
-
SQL Injection Prevention
- Use parameterized queries only
- NEVER concatenate user input into SQL
- Use ORM methods (Prisma, TypeORM)
-
Authentication
- Verify JWT token on all protected endpoints
- Check token expiration
- Validate user permissions
-
Rate Limiting
- Apply rate limits: 100 req/15min for API
- Stricter for auth endpoints: 5 req/15min
-
No Secrets in Code
- All secrets in environment variables
- Validate secrets on startup
Coverage: 90%+ required
-
Happy Path
it('should create user with valid data', async () => { const userData = { email: 'test@example.com', name: 'Test' }; const result = await service.create(userData); expect(result.success).toBe(true); expect(result.data.email).toBe(userData.email); });
-
Validation Errors
it('should return error for invalid email', async () => { const result = await service.create({ email: 'invalid' }); expect(result.success).toBe(false); });
-
Edge Cases
it('should handle duplicate email', async () => { // Test duplicate handling }); it('should handle database errors', async () => { // Test error handling });
-
Security
it('should reject requests without auth token', async () => { // Test authentication });
Use existing packages only:
- express / fastify / @nestjs/core
- zod (validation)
- jsonwebtoken (JWT)
- bcrypt (password hashing)
- prisma / typeorm (database)
DO NOT install new packages without approval
## Context
- Stack: Express.js 4.18 + TypeScript + Prisma + PostgreSQL
- Existing: User auth, database connection, error middleware
- Conventions: Async/await, Result<T,E>, dependency injection
## Task
Create POST /api/v1/products endpoint for adding products
## Requirements
- Product has: name, description, price, category, stock
- Only admins can create products
- Validate all inputs
- Check duplicate product names
- Return 201 with product on success
## Validation
- name: 2-200 chars, required
- description: 10-2000 chars, required
- price: positive number with 2 decimals
- category: enum ['electronics', 'clothing', 'food']
- stock: non-negative integer
## Security
- Require JWT auth + admin role
- Validate all inputs with Zod
- Rate limit: 20 requests per hour
## Tests
- Happy path with valid product
- Validation errors for each field
- Duplicate name rejection
- Non-admin rejection
- Database error handling
Generate: controller, service, repository, types, validator, testsBefore submitting AI-generated code:
- All inputs validated with Zod
- Parameterized queries (no string concatenation)
- Authentication middleware applied
- Rate limiting configured
- Error handling complete
- Tests cover all scenarios (90%+)
- No hardcoded secrets
- Functions under 50 lines
- TypeScript strict mode passes
- JSDoc comments on public methods
See also: