Backend Development
API Design
RESTful Conventions
GET /users # List usersPOST /users # Create userGET /users/:id # Get userPUT /users/:id # Update user (full)PATCH /users/:id # Update user (partial)DELETE /users/:id # Delete user
GET /users/:id/posts # List user's postsPOST /users/:id/posts # Create post for userResponse Format
json
{ "data": { ... }, "meta": { "page": 1, "per_page": 20, "total": 100 }}Error Format
json
{ "error": { "code": "VALIDATION_ERROR", "message": "Invalid input", "details": [ { "field": "email", "message": "Invalid format" } ] }}Database Patterns
Schema Design
sql
-- Use UUIDs for public IDsCREATE TABLE users ( id SERIAL PRIMARY KEY, public_id UUID DEFAULT gen_random_uuid() UNIQUE, email VARCHAR(255) UNIQUE NOT NULL, created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW());
-- Soft deletesALTER TABLE users ADD COLUMN deleted_at TIMESTAMPTZ;
-- IndexesCREATE INDEX idx_users_email ON users(email);CREATE INDEX idx_users_created ON users(created_at DESC);Query Patterns
sql
-- Pagination with cursorSELECT * FROM postsWHERE created_at < $cursorORDER BY created_at DESCLIMIT 20;
-- Efficient countingSELECT reltuples::bigint AS estimateFROM pg_class WHERE relname = 'users';Authentication
JWT Pattern
typescript
interface TokenPayload { sub: string; // User ID iat: number; // Issued at exp: number; // Expiration scope: string[]; // Permissions}
function verifyToken(token: string): TokenPayload { return jwt.verify(token, SECRET) as TokenPayload;}Middleware
typescript
async function authenticate(req: Request, res: Response, next: Next) { const token = req.headers.authorization?.replace('Bearer ', ''); if (!token) { return res.status(401).json({ error: 'Unauthorized' }); }
try { req.user = verifyToken(token); next(); } catch { res.status(401).json({ error: 'Invalid token' }); }}Caching Strategy
typescript
// Cache-aside patternasync function getUser(id: string): Promise<User> { const cached = await redis.get(`user:${id}`); if (cached) return JSON.parse(cached);
const user = await db.users.findById(id); await redis.setex(`user:${id}`, 3600, JSON.stringify(user)); return user;}
// Cache invalidationasync function updateUser(id: string, data: Partial<User>) { await db.users.update(id, data); await redis.del(`user:${id}`);}Rate Limiting
typescript
const limiter = rateLimit({ windowMs: 60 * 1000, // 1 minute max: 100, // 100 requests per window keyGenerator: (req) => req.ip, handler: (req, res) => { res.status(429).json({ error: 'Too many requests' }); }});Observability
- Logging: Structured JSON logs with request IDs
- Metrics: Request latency, error rates, queue depths
- Tracing: Distributed tracing with correlation IDs
- Health checks:
/healthand/readyendpoints


