A story from the journal
Learn the latest best practices for building robust, scalable APIs with Node.js, including security, performance, and architecture patterns.
Modern applications demand APIs that can handle millions of requests while maintaining performance, security, and reliability.
// Project structure src/ ├── controllers/ // Handle HTTP requests ├── services/ // Business logic ├── repositories/ // Data access layer ├── models/ // Data structures ├── middleware/ // Cross-cutting concerns └── utils/ // Helper functions
// controllers/userController.js class UserController { constructor(userService) { this.userService = userService; } async createUser(req, res, next) { try { const userData = req.body; const user = await this.userService.createUser(userData); res.status(201).json({ success: true, data: user, message: 'User created successfully' }); } catch (error) { next(error); } } }
// Bad: N+1 Query Problem const users = await User.findAll(); for (const user of users) { user.posts = await Post.findByUserId(user.id); } // Good: Use includes/joins const users = await User.findAll({ include: [{ model: Post, as: 'posts' }] });
// Redis caching middleware const cache = (duration = 300) => { return async (req, res, next) => { const key = req.originalUrl; const cached = await redis.get(key); if (cached) { return res.json(JSON.parse(cached)); } // Override res.json to cache response const originalJson = res.json; res.json = function(data) { redis.setex(key, duration, JSON.stringify(data)); originalJson.call(this, data); }; next(); }; };
const rateLimit = require('express-rate-limit'); const limiter = rateLimit({ windowMs: 15 * 60 * 1000, // 15 minutes max: 100, // limit each IP to 100 requests per windowMs message: 'Too many requests from this IP', standardHeaders: true, legacyHeaders: false, }); app.use('/api/', limiter);
const Joi = require('joi'); const userSchema = Joi.object({ email: Joi.string().email().required(), password: Joi.string().min(8).pattern( /^(?=.*[a-z])(?=.*[A-Z])(?=.*d)(?=.*[@$!%*?&])/ ).required(), age: Joi.number().integer().min(13).max(120) }); const validateUser = (req, res, next) => { const { error } = userSchema.validate(req.body); if (error) { return res.status(400).json({ success: false, message: error.details[0].message }); } next(); };
const helmet = require('helmet'); const cors = require('cors'); app.use(helmet({ contentSecurityPolicy: { directives: { defaultSrc: ["'self'"], styleSrc: ["'self'", "'unsafe-inline'"], }, }, hsts: { maxAge: 31536000, includeSubDomains: true, preload: true } })); app.use(cors({ origin: process.env.ALLOWED_ORIGINS?.split(',') || 'http://localhost:3000', credentials: true, optionsSuccessStatus: 200 }));
class AppError extends Error { constructor(message, statusCode) { super(message); this.statusCode = statusCode; this.isOperational = true; Error.captureStackTrace(this, this.constructor); } } const globalErrorHandler = (err, req, res, next) => { const statusCode = err.statusCode || 500; const message = err.isOperational ? err.message : 'Something went very wrong!'; res.status(statusCode).json({ status: 'error', message, // Add stack trace in development only stack: process.env.NODE_ENV === 'development' ? err.stack : undefined }); }; app.use(globalErrorHandler);
Sign in to share your thoughts on this story.
Hello, there!