Hritujeet
  • Blogs
  • Projects
  • Profile
  • Sign In
  • Sign Up
  • Blogs
  • Projects
  • Profile
  • Sign In
  • Sign Up
Hritujeet

Developer. Creator. Explorer.

Quick Links

  • Home
  • Blogs
  • Projects
  • About
  • Contact

Connect

GithubLinkedInTwitter
© 2025 Hritujeet Sharma. All rights reserved.

Building Scalable APIs: Node.js Best Practices for 2024

Blog featured image

Hritujeet

Author

2 months ago3 min read

Building Scalable APIs: Node.js Best Practices for 2024

Modern applications demand APIs that can handle millions of requests while maintaining performance, security, and reliability.

Architecture Patterns

Clean Architecture for APIs

// Project structure src/ ├── controllers/ // Handle HTTP requests ├── services/ // Business logic ├── repositories/ // Data access layer ├── models/ // Data structures ├── middleware/ // Cross-cutting concerns └── utils/ // Helper functions

Example Implementation

// 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); } } }

Performance Optimization

1. Database Query Optimization

// 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' }] });

2. Caching Strategies

// 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(); }; };

3. Rate Limiting

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);

Security Best Practices

Input Validation & Sanitization

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(); };

Security Headers & CORS

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 }));

Error Handling & Logging

Centralized Error Handler

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 Post Comment

Comments (0)

No comments yet. Be the first to comment!