0% found this document useful (0 votes)
20 views58 pages

Backend (NodeJS) DeveloperKit

The Backend (NodeJs) Developer Kit is a comprehensive guide for aspiring and experienced Node.js developers, covering essential topics from environment setup to advanced backend development concepts. It includes practical coding challenges, interview questions, and best practices for building robust applications with Node.js and Express. The kit is designed to facilitate step-by-step learning and hands-on practice for mastering backend development skills.

Uploaded by

dapilot171
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
20 views58 pages

Backend (NodeJS) DeveloperKit

The Backend (NodeJs) Developer Kit is a comprehensive guide for aspiring and experienced Node.js developers, covering essential topics from environment setup to advanced backend development concepts. It includes practical coding challenges, interview questions, and best practices for building robust applications with Node.js and Express. The kit is designed to facilitate step-by-step learning and hands-on practice for mastering backend development skills.

Uploaded by

dapilot171
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 58

Backend (NodeJs) Developer Kit

- Sample
Hello and welcome! I'm Parikh Jain, and I'm excited to share with you the
ultimate guide to become a MERN stack full stack developer. This kit is a labor
of love, drawn from my extensive journey as an SDE at Amazon, a founding
member at Coding Ninjas, and the founder of ProPeers. I’ve distilled my real-
world experience into a comprehensive resource that covers every topic you
need to excel.

This kit covers:

1. Introduction & Overview

2. Environment Setup & Tools

3. Backend Fundamentals with Express

4. REST API Development

5. Database Integration

6. Authentication & Authorization

7. Testing & Quality Assurance

8. Caching, Performance & Rate Limiting

9. Real-Time Communication

10. DevOps & Deployment

11. Machine Coding Challenges

1. Introduction & Overview


Purpose of the Kit

Backend (NodeJs) Developer Kit - Sample 1


This guide is designed to help aspiring and experienced Node.js backend
developers master the fundamentals and advanced topics of backend
development using Node.js. It covers everything from setting up your environment
to designing scalable, secure APIs and integrating with databases. In addition, the
guide provides curated interview questions and coding challenges to prepare you
for technical discussions and real-world scenarios.

Target Audience
Aspiring Node.js Developers: Beginners who want to learn Node.js
fundamentals and build a strong foundation in backend development.

Experienced Developers: Engineers looking to refresh their knowledge, learn


advanced concepts, or prepare for Node.js backend interviews.

Full-Stack Developers: Those working with both frontend and backend


technologies who need a deeper understanding of Node.js for building robust,
scalable applications.

How to Use This Guide


Step-by-Step Learning: Follow the sections sequentially to build a
comprehensive understanding—from environment setup to advanced topics
like DevOps and real-time communication.

Interview Preparation: Focus on the dedicated interview questions and


machine coding challenges in each section to practice and prepare for
technical interviews.

Hands-On Practice: Implement the provided code snippets and modify them
to suit your project requirements. Use the challenges as a starting point to
build more complex systems.

Reference Material: Use the Additional Resources section for further reading,
exploring useful Node.js packages, and staying updated with the latest trends.

Important Concepts
What is Node.js?

Backend (NodeJs) Developer Kit - Sample 2


Node.js is a JavaScript runtime built on Chrome's V8 JavaScript engine. It
allows developers to run JavaScript on the server side, enabling the creation
of scalable network applications.

Event-Driven Architecture:
Node.js uses a non-blocking, event-driven architecture that makes it
lightweight and efficient—ideal for data-intensive real-time applications.

Single-Threaded Model with Asynchronous I/O:


Despite being single-threaded, Node.js handles concurrent operations using
its event loop, which processes I/O-bound tasks asynchronously. This model
is especially useful for building APIs and web applications that need to handle
multiple requests concurrently.

NPM and the Ecosystem:

Node Package Manager (npm) is a powerful tool that gives access to


thousands of open-source packages and libraries, significantly speeding up
the development process.

Full-Stack Integration:
Node.js seamlessly integrates with various frontend frameworks (like React,
Angular, or Vue) and databases (like MongoDB) to build modern full-stack
applications.

Interview Questions for Section 1


Here are some sample interview questions related to the introduction and
overview of Node.js development:

1. What is Node.js and why is it popular for backend development?

Expected Answer: Node.js is a runtime environment that allows you to run


JavaScript on the server side. It is popular due to its non-blocking, event-
driven architecture, which makes it highly efficient for building scalable, data-
intensive applications.

2. Explain the concept of asynchronous programming in Node.js. How does it


differ from traditional multi-threaded programming?

Backend (NodeJs) Developer Kit - Sample 3


Expected Answer: In Node.js, asynchronous programming allows operations to
be executed without blocking the main thread. This is achieved via callbacks,
promises, and async/await, enabling efficient handling of I/O-bound tasks.
Unlike traditional multi-threaded programming, Node.js relies on a single-
threaded event loop to manage concurrency.

3. What is the role of npm in Node.js development?

Expected Answer: npm (Node Package Manager) is the default package


manager for Node.js, providing access to a vast repository of open-source
libraries and tools. It simplifies dependency management, script execution,
and project configuration.

4. How does Node.js' event loop work?


Expected Answer: The event loop is the core mechanism in Node.js that
handles asynchronous operations. It continuously monitors the call stack and
the callback queue, processing events and callbacks in a non-blocking
manner. This allows Node.js to handle many concurrent operations with a
single thread.

5. What are some common use cases for Node.js?

Expected Answer: Node.js is widely used for building REST APIs, real-time
applications (e.g., chat apps, live dashboards), microservices, single-page
applications (SPAs), and data streaming applications.

This introductory section sets the stage for the rest of the guide. It provides an
overview of what Node.js is, its key advantages, and how it fits into modern
backend development. The interview questions help assess your foundational
knowledge and understanding of the Node.js ecosystem.

2. Environment Setup & Tools


This section establishes the foundation for Node.js backend development by
teaching you how to set up your development environment, initialize your project,

Backend (NodeJs) Developer Kit - Sample 4


manage dependencies, configure npm scripts, and work with essential tools like
Git and your IDE.

Part 2.1: Concepts & Code Snippets


2.1.1 Installing Node.js and npm

Important Concepts
Node.js Runtime:
Node.js is a JavaScript runtime built on Chrome's V8 engine that allows
JavaScript to be executed on the server side.

npm (Node Package Manager):

npm is used to install, manage, and update Node.js packages and libraries.

Steps & Code Snippets


1. Download and Install:

Visit the Node.js official website and download the LTS version.

2. Verify Installation:

Run the following commands in your terminal:

bash
Copy
node -v
npm -v

Expected output: Version numbers for Node.js and npm.

2.1.2 Project Initialization

Important Concepts
Project Metadata:

Backend (NodeJs) Developer Kit - Sample 5


The package.json file stores metadata (name, version, dependencies, scripts,
etc.) for your project.

npm Initialization:

Use npm init (or npm init -y for default settings) to generate the package.json file.

Code Snippet: Initialize a New Project

bash
Copy
npm init -y

This command creates a default package.json file.

Sample package.json

json
Copy
{
"name": "node-backend-project",
"version": "1.0.0",
"description": "A sample Node.js backend project",
"main": "server.js",
"scripts": {
"start": "node server.js",
"dev": "nodemon server.js",
"test": "jest"
},
"author": "Your Name",
"license": "ISC",
"dependencies": {
"express": "^4.18.2"
},
"devDependencies": {
"nodemon": "^2.0.20",

Backend (NodeJs) Developer Kit - Sample 6


"jest": "^29.0.0"
}
}

2.1.3 Managing Dependencies & npm Scripts

Important Concepts
Installing Dependencies:

Use npm install <package> to add a package to your project.

npm Scripts:

Scripts defined in package.json automate tasks like starting the server or running
tests.

Code Snippets
1. Install Express:

npm install express

2. Defining npm Scripts in package.json :

"scripts": {
"start": "node server.js",
"dev": "nodemon server.js",
"test": "jest"
}

3. Running Scripts:

Backend (NodeJs) Developer Kit - Sample 7


npm start # Starts the server
npm run dev # Starts the server with hot-reloading (nodemon)
npm test # Runs tests with Jest

2.1.4 Essential Tools & IDE Recommendations

Important Concepts
Integrated Development Environments (IDEs):

Tools like Visual Studio Code (VS Code) and WebStorm provide rich features
(debugging, extensions, Git integration) for Node.js development.

Useful Extensions for VS Code:

ESLint: Ensures consistent coding style.

Prettier: Automatically formats your code.

GitLens: Enhances Git capabilities.

Version Control:
Use Git to manage source code. Create a .gitignore file to exclude files such as
node_modules/ .

Code Snippets
1. VS Code Settings ( .vscode/settings.json ):

{
"editor.formatOnSave": true,
"eslint.alwaysShowStatus": true,
"gitlens.advanced.messages": {
"suppressShowKeyBindingsNotice": true}

Backend (NodeJs) Developer Kit - Sample 8


}

2. Git Setup:

Initialize a Git Repository:

git init

Create a .gitignore File:

node_modules/
.env

Common Git Commands:

git add .
git commit -m "Initial commit"
git push origin main

Part 2.2: Interview Questions & Code Challenges


This part provides a series of interview questions related to environment setup
and tooling, along with sample solutions and code snippets.

Sample Interview Question 1


Q: How do you verify that Node.js and npm are correctly installed on your system?

Answer:

Backend (NodeJs) Developer Kit - Sample 9


Explanation: Open your terminal and run:

node -v
npm -v

Expected Output: Version numbers for both Node.js and npm confirm proper
installation.

Sample Interview Question 2


Q: How can npm scripts help streamline development workflows, and how do you
run them?

Answer:

Explanation: npm scripts automate common tasks like starting the server,
running tests, or launching development tools. They are defined in the scripts
section of package.json and can be run using npm start or npm run <script-name> .

Code Example: (Sample snippet from package.json )

"scripts": {
"start": "node server.js",
"dev": "nodemon server.js",
"test": "jest"
}

Run Script:

npm start

Backend (NodeJs) Developer Kit - Sample 10


3. Backend Fundamentals with Express
Express is a minimal and flexible web framework for Node.js that allows you to
build robust backend applications quickly. In this section, you'll learn how to set
up an Express server, implement routing and middleware, and handle errors and
logging.

Part 3.1: Concepts & Code Snippets


3.1.1 Setting Up an Express Server
Key Concepts:

Express Instance:

Create an instance of Express to handle HTTP requests.

Middleware:

Functions that process requests and responses before reaching your route
handlers.

Code Example: Basic Express Server

// server.js
const express = require('express');
const app = express();
const PORT = process.env.PORT || 3000;

// Middleware to parse JSON payloads


app.use(express.json());

Backend (NodeJs) Developer Kit - Sample 11


// Basic route: GET /
app.get('/', (req, res) => {
res.send('Hello, Express!');
});

// Start the server


app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`);
});

3.1.2 Routing & Middleware


Key Concepts:

Routing:

Define endpoints to respond to different HTTP methods (GET, POST, etc.).

Middleware Functions:

Functions that intercept and process requests before passing them on to the
next handler.

Code Example: Defining Routes in a Separate Router

// routes/greeting.js
const express = require('express');
const router = express.Router();

// Define a GET endpoint at /api/greeting


router.get('/greeting', (req, res) => {
const name = req.query.name || 'Guest';
res.json({ message: `Hello, ${name}!` });
});

Backend (NodeJs) Developer Kit - Sample 12


module.exports = router;

Integrate the route in your main server:

// server.js (continued)
const greetingRoute = require('./routes/greeting');
app.use('/api', greetingRoute);

Code Example: Logging Middleware

// middleware/logger.js
function logger(req, res, next) {
console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`);
next();
}

module.exports = logger;

Usage in server.js:

const logger = require('./middleware/logger');


app.use(logger);

3.1.3 Error Handling & Logging


Key Concepts:

Error Handling Middleware:

Special middleware to catch and handle errors.

Backend (NodeJs) Developer Kit - Sample 13


Request Logging:
Use libraries like Morgan to log HTTP requests automatically.

Code Example: Error Handling Middleware

// middleware/errorHandler.js
function errorHandler(err, req, res, next) {
console.error('Error:', err.stack);
res.status(500).json({ error: 'Something went wrong!' });
}

module.exports = errorHandler;

Integrate in server.js (after all routes):

const errorHandler = require('./middleware/errorHandler');


app.use(errorHandler);

Code Example: HTTP Request Logging with Morgan

const morgan = require('morgan');


// Log requests in development mode
app.use(morgan('dev'));

Part 3.2: Interview Questions & Code Challenges


Below are some practical interview questions along with code snippet solutions
that cover the key aspects of Express development.

Backend (NodeJs) Developer Kit - Sample 14


Sample Interview Question 1
Q: What is the difference between app.use() and router.use() in Express?
Answer:

app.use() applies middleware at the application level to every route.

router.use() applies middleware only to the routes defined within that router.
Code Example:

// Global middleware using app.use()


app.use((req, res, next) => {
console.log('Global middleware');
next();
});

// Router-specific middleware
const router = express.Router();
router.use((req, res, next) => {
console.log('Router-specific middleware');
next();
});
router.get('/test', (req, res) => res.send('Test route'));
app.use('/api', router);

Sample Interview Question 2


Q: How can you modularize routes in an Express application?

Answer:
You can create separate router modules and use app.use() to mount them on
specific paths.

Backend (NodeJs) Developer Kit - Sample 15


Code Example:

// In routes/users.js
const express = require('express');
const router = express.Router();

router.get('/', (req, res) => {


res.json({ message: 'List of users' });
});

module.exports = router;

// In server.js
const usersRouter = require('./routes/users');
app.use('/api/users', usersRouter);

4. REST API Development


Part 4.1: Concepts & Code Snippets
Key Concepts
REST Principles:

Representational State Transfer (REST) is an architectural style that defines a


set of constraints and properties based on HTTP. It emphasizes stateless
interactions and resource-based URLs.

HTTP Methods:

GET: Retrieve data.

POST: Create new resources.

Backend (NodeJs) Developer Kit - Sample 16


PUT/PATCH: Update existing resources.

DELETE: Remove resources.

Status Codes:
Use proper HTTP status codes (e.g., 200, 201, 400, 404, 500) to communicate
the outcome of API requests.

Routing & Endpoints:


Define resource endpoints that accept parameters via URL (route parameters),
query strings, and request bodies.

Data Validation:

Validate incoming data to ensure correctness using libraries like express-


validator or custom middleware.

API Versioning:
Organize endpoints into versions (e.g., /api/v1/ ) to handle changes over time.

Code Example: Implementing a REST API for a "User" Resource


Below is an example demonstrating basic CRUD operations using Express:

1. Define a Router for Users

// routes/users.js
const express = require('express');
const router = express.Router();

// In-memory array to simulate a database


let users = [
{ id: 1, name: 'Alice', email: '[email protected]' },
{ id: 2, name: 'Bob', email: '[email protected]' }
];

// GET /api/users - Get all users


router.get('/', (req, res) => {

Backend (NodeJs) Developer Kit - Sample 17


res.status(200).json(users);
});

// GET /api/users/:id - Get user by ID


router.get('/:id', (req, res) => {
const user = users.find(u => u.id === parseInt(req.params.id));
if (!user) return res.status(404).json({ error: 'User not found' });
res.status(200).json(user);
});

// POST /api/users - Create a new user


router.post('/', (req, res) => {
const { name, email } = req.body;
const newUser = { id: users.length + 1, name, email };
users.push(newUser);
res.status(201).json(newUser);
});

// PUT /api/users/:id - Update an existing user


router.put('/:id', (req, res) => {
const user = users.find(u => u.id === parseInt(req.params.id));
if (!user) return res.status(404).json({ error: 'User not found' });
const { name, email } = req.body;
user.name = name || user.name;
user.email = email || user.email;
res.status(200).json(user);
});

// DELETE /api/users/:id - Delete a user


router.delete('/:id', (req, res) => {
const index = users.findIndex(u => u.id === parseInt(req.params.id));
if (index === -1) return res.status(404).json({ error: 'User not found' });
const deletedUser = users.splice(index, 1);
res.status(200).json(deletedUser);
});

Backend (NodeJs) Developer Kit - Sample 18


module.exports = router;

2. Integrate the User Router in the Main Server

// server.js
const express = require('express');
const app = express();
const PORT = process.env.PORT || 3000;

// Middleware to parse JSON payloads


app.use(express.json());

// Mount the users router at /api/users


const usersRouter = require('./routes/users');
app.use('/api/users', usersRouter);

// Global error handler (optional, see next section for more on error handling)
app.use((err, req, res, next) => {
console.error('Error:', err.stack);
res.status(500).json({ error: 'Internal Server Error' });
});

// Start the server


app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`);
});

Part 4.2: Interview Questions & Code Challenges (15+)


Below are 15+ targeted interview questions for REST API development, each with
a brief explanation and sample code snippet solutions.

Backend (NodeJs) Developer Kit - Sample 19


Sample Interview Question 1
Q: How do you validate request data in Express?
Answer:

Explanation: You can use middleware like express-validator to validate and


sanitize incoming data.

Code Example:

const { body, validationResult } = require('express-validator');

router.post('/',
body('name').notEmpty().withMessage('Name is required'),
body('email').isEmail().withMessage('Valid email is required'),
(req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
// Proceed to create user...
}
);

Sample Interview Question 2


Q: How do you implement a PUT endpoint to update a resource?
Answer:

Code Example:

Backend (NodeJs) Developer Kit - Sample 20


router.put('/:id', (req, res) => {
const user = users.find(u => u.id === parseInt(req.params.id));
if (!user) return res.status(404).json({ error: 'User not found' });
const { name, email } = req.body;
user.name = name || user.name;
user.email = email || user.email;
res.status(200).json(user);
});

5. Database Integration
Modern Node.js backend applications often use NoSQL databases like MongoDB
for flexibility and scalability. Mongoose is a popular ODM (Object Data Modeling)
library that simplifies working with MongoDB in Node.js.

Part 5.1: Concepts & Code Snippets


5.1.1 Connecting to MongoDB with Mongoose
Key Concepts:

MongoDB:
A NoSQL database that stores data in JSON-like documents.

Mongoose:
An ODM that provides a straightforward schema-based solution to model
application data.

Code Snippet: Mongoose Connection

// db.js
const mongoose = require('mongoose');

Backend (NodeJs) Developer Kit - Sample 21


const connectDB = async () => {
try {
await mongoose.connect('mongodb://localhost:27017/myapp', {
useNewUrlParser: true,
useUnifiedTopology: true,
});
console.log('MongoDB connected successfully');
} catch (error) {
console.error('MongoDB connection error:', error);
process.exit(1);
}
};

module.exports = connectDB;

Integrate in your server.js:

// server.js (at the top)


const connectDB = require('./db');
connectDB();

5.1.2 Defining Mongoose Schemas & Models


Key Concepts:

Schema Definition:
Define the structure of your documents using Mongoose schemas.

Models:
Create models based on schemas to interact with the corresponding
MongoDB collections.

Backend (NodeJs) Developer Kit - Sample 22


Code Snippet: User Model

// models/User.js
const mongoose = require('mongoose');

const UserSchema = new mongoose.Schema({


username: { type: String, required: true, unique: true },
email: { type: String, required: true, unique: true },
age: { type: Number, min: 0 }
}, { timestamps: true });

module.exports = mongoose.model('User', UserSchema);

5.1.3 Performing CRUD Operations


Key Concepts:

Create, Read, Update, Delete (CRUD):

Basic operations to manage resources.

Express Integration:
Use Mongoose within Express routes to handle database operations.

Code Snippet: CRUD Endpoints for Users

// routes/users.js
const express = require('express');
const router = express.Router();
const User = require('../models/User');

// Create a new user


router.post('/', async (req, res, next) => {
try {

Backend (NodeJs) Developer Kit - Sample 23


const newUser = new User(req.body);
const savedUser = await newUser.save();
res.status(201).json(savedUser);
} catch (err) {
next(err);
}
});

// Get all users


router.get('/', async (req, res, next) => {
try {
const users = await User.find();
res.status(200).json(users);
} catch (err) {
next(err);
}
});

// Get user by ID
router.get('/:id', async (req, res, next) => {
try {
const user = await User.findById(req.params.id);
if (!user) return res.status(404).json({ error: 'User not found' });
res.status(200).json(user);
} catch (err) {
next(err);
}
});

// Update user by ID
router.put('/:id', async (req, res, next) => {
try {
const updatedUser = await User.findByIdAndUpdate(
req.params.id,
req.body,
{ new: true, runValidators: true }

Backend (NodeJs) Developer Kit - Sample 24


);
if (!updatedUser) return res.status(404).json({ error: 'User not found' });
res.status(200).json(updatedUser);
} catch (err) {
next(err);
}
});

// Delete user by ID
router.delete('/:id', async (req, res, next) => {
try {
const deletedUser = await User.findByIdAndDelete(req.params.id);
if (!deletedUser) return res.status(404).json({ error: 'User not found' });
res.status(200).json(deletedUser);
} catch (err) {
next(err);
}
});

module.exports = router;

Integrate this route in your main server:

const userRoutes = require('./routes/users');


app.use('/api/users', userRoutes);

5.1.4 Advanced Querying & Pagination


Key Concepts:

Filtering, Sorting, and Pagination:


Use query parameters to filter data and paginate results.

Backend (NodeJs) Developer Kit - Sample 25


Mongoose Query Methods:
Methods like .find() , .limit() , .skip() , and .sort() .

Code Snippet: Implementing Pagination

// routes/users.js (add this endpoint)


router.get('/paginated', async (req, res, next) => {
try {
const page = parseInt(req.query.page) || 1;
const limit = parseInt(req.query.limit) || 10;
const skip = (page - 1) * limit;
const users = await User.find().skip(skip).limit(limit).sort({ username: 1 });
res.status(200).json(users);
} catch (err) {
next(err);
}
});

5.1.5 Schema Relationships & Middleware


Key Concepts:

Relationships:
Embedding vs. referencing documents.

Middleware (Hooks):
Pre/post hooks in Mongoose to perform actions before or after operations.

Code Snippet: User and Post Relationship Example

// models/Post.js
const mongoose = require('mongoose');

const PostSchema = new mongoose.Schema({

Backend (NodeJs) Developer Kit - Sample 26


title: { type: String, required: true },
content: String,
user: { type: mongoose.Schema.Types.ObjectId, ref: 'User' }
}, { timestamps: true });

module.exports = mongoose.model('Post', PostSchema);

In the User model, you can reference posts (if needed) or simply populate posts in
your queries:

// Query with population example:


User.findById(userId).populate('posts').exec((err, user) => {
// user.posts will contain the related posts
});

Part 5.2: Interview Questions & Code Challenges (15+)


Below are 15+ interview questions for Database Integration with Mongoose, each
with an explanation and sample code snippets.

Sample Interview Question 1


Q: How do you implement pagination in a Mongoose query?
Answer:

Code Example:

(Refer to the pagination endpoint snippet in Part 5.1.4)

const page = parseInt(req.query.page) || 1;


const limit = parseInt(req.query.limit) || 10;

Backend (NodeJs) Developer Kit - Sample 27


const skip = (page - 1) * limit;

User.find().skip(skip).limit(limit)
.then(users => res.json(users))
.catch(err => next(err));

Sample Interview Question 2


Q: How do you use Mongoose middleware (hooks) to perform actions before
saving a document?
Answer:

Code Example:

UserSchema.pre('save', function(next) {
console.log('Before saving user:', this);
next();
});

This hook runs before a user document is saved.

6. Authentication & Authorization


Part 6.1: Concepts & Code Snippets
6.1.1 Implementing JWT-Based Authentication
Key Concepts:

JWT (JSON Web Tokens):

A compact, URL-safe means of representing claims between two parties.


Used for stateless authentication.

Backend (NodeJs) Developer Kit - Sample 28


jsonwebtoken Library:
A popular Node.js library for generating and verifying JWTs.

Code Example: Generating a JWT Token

// routes/auth.js
const express = require('express');
const jwt = require('jsonwebtoken');
const router = express.Router();
const secret = process.env.JWT_SECRET || 'your_jwt_secret';

// Login route: In a real app, verify user credentials from a database


router.post('/login', (req, res) => {
const { username } = req.body;
// For demonstration, we assume any provided username is valid
const token = jwt.sign({ username }, secret, { expiresIn: '1h' });
res.status(200).json({ token });
});

module.exports = router;

Code Example: Verifying a JWT with Middleware

// middleware/authenticate.js
const jwt = require('jsonwebtoken');
const secret = process.env.JWT_SECRET || 'your_jwt_secret';

function authenticateToken(req, res, next) {


const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1]; // Bearer TOKEN
if (!token) return res.sendStatus(401);

jwt.verify(token, secret, (err, user) => {

Backend (NodeJs) Developer Kit - Sample 29


if (err) return res.sendStatus(403);
req.user = user; // Attach user info to request
next();
});
}

module.exports = authenticateToken;

Code Example: Protecting a Route with JWT Middleware

// routes/protected.js
const express = require('express');
const router = express.Router();
const authenticateToken = require('../middleware/authenticate');

router.get('/protected', authenticateToken, (req, res) => {


res.status(200).json({ message: `Hello, ${req.user.username}. You have acc
ess to protected data!` });
});

module.exports = router;

6.1.2 Secure Password Storage Using bcrypt


Key Concepts:

bcrypt:
A widely used library for hashing and comparing passwords securely.

Code Example: Hashing a Password

// utils/hashPassword.js
const bcrypt = require('bcrypt');

Backend (NodeJs) Developer Kit - Sample 30


async function hashPassword(password) {
const saltRounds = 10;
return await bcrypt.hash(password, saltRounds);
}

// Example usage:
hashPassword('myPlainPassword')
.then(hashed => console.log('Hashed password:', hashed))
.catch(err => console.error(err));

module.exports = hashPassword;

Code Example: Verifying a Password

// utils/verifyPassword.js
const bcrypt = require('bcrypt');

async function verifyPassword(plainPassword, hashedPassword) {


return await bcrypt.compare(plainPassword, hashedPassword);
}

// Example usage:
const plain = 'myPlainPassword';
const hashed = '$2b$10$D4G5f18o7aMMfwasBlh6Lu...'; // Example hash
verifyPassword(plain, hashed)
.then(match => console.log('Password match:', match))
.catch(err => console.error(err));

module.exports = verifyPassword;

6.1.3 Combining Authentication & Authorization in Routes

Backend (NodeJs) Developer Kit - Sample 31


Integrate the authentication and password verification into your user registration
and login flows, then protect routes using middleware.
Code Example: User Registration & Login Routes

// routes/usersAuth.js
const express = require('express');
const bcrypt = require('bcrypt');
const jwt = require('jsonwebtoken');
const router = express.Router();
const secret = process.env.JWT_SECRET || 'your_jwt_secret';

// Simulated user "database"


let users = [];

// User Registration
router.post('/register', async (req, res) => {
const { username, password, email } = req.body;
const hashedPassword = await bcrypt.hash(password, 10);
const newUser = { id: users.length + 1, username, email, password: hashedP
assword };
users.push(newUser);
res.status(201).json({ message: 'User registered successfully' });
});

// User Login
router.post('/login', async (req, res) => {
const { username, password } = req.body;
const user = users.find(u => u.username === username);
if (!user) return res.status(400).json({ error: 'User not found' });

const validPassword = await bcrypt.compare(password, user.password);


if (!validPassword) return res.status(400).json({ error: 'Invalid password' });

const token = jwt.sign({ id: user.id, username: user.username }, secret, { expi

Backend (NodeJs) Developer Kit - Sample 32


resIn: '1h' });
res.status(200).json({ token });
});

module.exports = router;

Part 6.2: Interview Questions & Code Challenges


Below are 15+ targeted interview questions for Authentication & Authorization in
Node.js with sample code snippet solutions.

Sample Interview Question 1


Q: How do you generate a JWT token in Node.js?
Answer:

Code Example:

const jwt = require('jsonwebtoken');


const secret = process.env.JWT_SECRET || 'your_jwt_secret';

function generateToken(user) {
return jwt.sign({ id: user.id, username: user.username }, secret, { expiresI
n: '1h' });
}

// Usage in a login route


const token = generateToken({ id: 1, username: 'alice' });
console.log('JWT Token:', token);

Backend (NodeJs) Developer Kit - Sample 33


Sample Interview Question 2
Q: How do you verify a JWT token in Express middleware?
Answer:

Code Example:
(See the authenticateToken middleware snippet in Part 6.1.1.)

Interview Question 4
Q: How do you protect a route so that only authenticated users can access it?
Answer:

Code Example:

const authenticateToken = require('./middleware/authenticate');

app.get('/api/secure-data', authenticateToken, (req, res) => {


res.status(200).json({ message: `Hello, ${req.user.username}!` });
});

7. Testing & Quality Assurance


Testing is essential for ensuring that your Node.js backend functions correctly and
remains robust as your application evolves. In this section, you'll learn about unit
testing, integration testing, and how to integrate testing into your CI/CD pipeline.

Part 7.1: Concepts & Code Snippets


7.1.1 Unit Testing with Jest
Key Concepts:

Backend (NodeJs) Developer Kit - Sample 34


Unit Tests:
Verify the functionality of individual units (functions, modules) in isolation.

Jest:

A popular testing framework for Node.js that supports mocking, snapshot


testing, and more.

Code Example: Unit Test for a Simple Function

// utils/math.js
function add(a, b) {
return a + b;
}
module.exports = { add };

// tests/math.test.js
const { add } = require('../utils/math');

test('adds 2 + 3 to equal 5', () => {


expect(add(2, 3)).toBe(5);
});

Run tests using:

npm test

7.1.2 Integration Testing with Supertest


Key Concepts:

Backend (NodeJs) Developer Kit - Sample 35


Integration Tests:
Verify that different parts of your application work together by testing API
endpoints end-to-end.

Supertest:
A library for testing HTTP endpoints in Node.js by simulating requests.

Code Example: Integration Test for an API Endpoint

// server.js
const express = require('express');
const app = express();
const PORT = process.env.PORT || 3000;

app.use(express.json());

app.get('/api/hello', (req, res) => {


res.status(200).json({ message: 'Hello, World!' });
});

if (process.env.NODE_ENV !== 'test') {


app.listen(PORT, () => console.log(`Server running on port ${PORT}`));
}

module.exports = app;

// tests/api.test.js
const request = require('supertest');
const app = require('../server');

describe('GET /api/hello', () => {


it('should return a greeting message', async () => {

Backend (NodeJs) Developer Kit - Sample 36


const res = await request(app).get('/api/hello');
expect(res.statusCode).toEqual(200);
expect(res.body).toHaveProperty('message', 'Hello, World!');
});
});

7.1.3 Test-Driven Development (TDD) Practices


Key Concepts:

TDD:
Write tests before writing the actual code. This ensures that your code meets
the specified requirements.

Cycle:
Red (fail) → Green (pass) → Refactor.

Code Example: Simple TDD Workflow

1. Write a failing test:

// tests/counter.test.js
const { increment } = require('../utils/counter');
test('increment should add 1 to the number', () => {
expect(increment(1)).toBe(2);
});

2. Write the minimal code to pass the test:

// utils/counter.js
function increment(n) {
return n + 1;
}

Backend (NodeJs) Developer Kit - Sample 37


module.exports = { increment };

3. Run tests and refactor as needed.

7.1.4 Continuous Integration (CI) Integration


Key Concepts:

CI Pipelines:
Automate tests on every push/commit using tools like GitHub Actions or
Jenkins.

Example Workflow (GitHub Actions):

# .github/workflows/nodejs.yml
name: Node.js CI

on: [push, pull_request]

jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [14.x, 16.x]
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node-version }}
- run: npm install
- run: npm test

Backend (NodeJs) Developer Kit - Sample 38


Part 7.2: Interview Questions & Code Challenges (15+)
Below are over 15 targeted interview questions for Testing & Quality Assurance in
Node.js, each with an explanation and code snippet solution.

Sample Interview Question 1


Q: How do you test an Express API endpoint using Supertest?
A:

Code Example:

const request = require('supertest');


const app = require('../server');

test('GET /api/hello returns greeting', async () => {


const response = await request(app).get('/api/hello');
expect(response.statusCode).toBe(200);
expect(response.body.message).toBe('Hello, World!');
});

Sample Interview Question 2


Q: How do you mock external dependencies in Jest?
A:

Answer:
Use Jest’s built-in mocking functions to simulate external modules.

Code Example:

// Suppose we have a module that fetches data from an API

Backend (NodeJs) Developer Kit - Sample 39


const axios = require('axios');
jest.mock('axios');

test('should fetch user data', async () => {


const data = { data: { name: 'Alice' } };
axios.get.mockResolvedValue(data);
const result = await axios.get('/user');
expect(result.data.name).toBe('Alice');
});

8. Caching, Performance & Rate Limiting


Part 8.1: Concepts & Code Snippets
8.1.1 Caching with Redis
Key Concepts:

Caching:
Storing frequently accessed data in memory to reduce latency and improve
throughput.

Redis:
An in-memory data structure store, used as a cache, message broker, and
more.

Code Example: Integrating Redis with Node.js

1. Setup and Installation:

npm install redis

Backend (NodeJs) Developer Kit - Sample 40


2. Basic Redis Integration:

// redisClient.js
const redis = require('redis');
const client = redis.createClient({ host: '127.0.0.1', port: 6379 });

client.on('error', (err) => {


console.error('Redis error:', err);
});

client.on('connect', () => {
console.log('Connected to Redis');
});

module.exports = client;

3. Using Redis to Cache API Responses:

// routes/data.js
const express = require('express');
const router = express.Router();
const redisClient = require('../redisClient');

// Example API endpoint with caching


router.get('/data', (req, res, next) => {
const key = 'api:data';
redisClient.get(key, async (err, cachedData) => {
if (err) return next(err);
if (cachedData) {
return res.status(200).json(JSON.parse(cachedData));
}
// Simulate data fetching (e.g., from a database)

Backend (NodeJs) Developer Kit - Sample 41


const data = { message: 'Fresh data from DB' };
// Cache data for 1 hour
redisClient.setex(key, 3600, JSON.stringify(data));
res.status(200).json(data);
});
});

module.exports = router;

8.1.2 Performance Optimization Techniques


Key Concepts:

Lean Queries:
In MongoDB/Mongoose, using .lean() returns plain JavaScript objects instead
of Mongoose documents, reducing overhead.

Efficient Data Structures:


Choosing appropriate data structures for in-memory operations.

Code Profiling:
Use tools like Node.js built-in profiler or external tools (e.g., Clinic.js) to
identify bottlenecks.

Code Example: Using .lean() in Mongoose Query

// Example usage in a route


router.get('/users/lean', async (req, res, next) => {
try {
const users = await User.find().lean(); // Returns plain objects
res.status(200).json(users);
} catch (err) {
next(err);
}

Backend (NodeJs) Developer Kit - Sample 42


});

8.1.3 Rate Limiting in Express


Key Concepts:

Rate Limiting:
Prevents abuse and ensures fair usage by limiting the number of requests per
client within a specified time window.

express-rate-limit:
A middleware to apply rate limiting on Express routes.

Code Example: Implementing Rate Limiting

1. Installation:

npm install express-rate-limit

2. Setting Up Rate Limiting Middleware:

// middleware/rateLimiter.js
const rateLimit = require('express-rate-limit');

// Allow 100 requests per 15 minutes per IP


const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100,
message: 'Too many requests from this IP, please try again later.'
});

Backend (NodeJs) Developer Kit - Sample 43


module.exports = limiter;

3. Using Rate Limiter in Express:

// server.js (or within specific routes)


const rateLimiter = require('./middleware/rateLimiter');
app.use('/api/', rateLimiter);

Part 8.2: Interview Questions & Code Challenges (15+)


Below are 15+ targeted interview questions for Caching, Performance, and Rate
Limiting in Node.js, along with sample code snippets.

Sample Interview Question


Q: How would you test if your Redis caching layer is working correctly?
Answer:

Code Example:

// Test route to verify caching


router.get('/test-cache', (req, res, next) => {
const key = 'test:key';
redisClient.get(key, (err, data) => {
if (data) {
return res.json({ cached: true, data: JSON.parse(data) });
}
const freshData = { value: 'fresh data' };
redisClient.setex(key, 3600, JSON.stringify(freshData));
res.json({ cached: false, data: freshData });
});

Backend (NodeJs) Developer Kit - Sample 44


});

9. Real-Time Communication
Part 9.1: Concepts & Code Snippets
Key Concepts
Real-Time Communication:
Enables bi-directional, persistent communication between clients and the
server.

WebSockets:
A protocol that provides full-duplex communication channels over a single
TCP connection.

Socket.io:
A Node.js library that simplifies real-time communication by providing
fallbacks (like long polling) when WebSockets are not available, as well as
additional features such as automatic reconnection, rooms, and namespaces.

Broadcasting & Rooms:


Ability to send messages to all connected clients or to groups (rooms) of
clients.

Handling Connections:
Managing client connections, disconnections, and error events.

Code Example 1: Basic Socket.io Server Integration

// server.js
const express = require('express');
const http = require('http');

Backend (NodeJs) Developer Kit - Sample 45


const socketIo = require('socket.io');

const app = express();


const server = http.createServer(app);
const io = socketIo(server); // Initialize Socket.io with the HTTP server

// Serve static files (e.g., client HTML)


app.use(express.static('public'));

// Listen for client connections


io.on('connection', (socket) => {
console.log('New client connected:', socket.id);

// Listen for messages from clients


socket.on('message', (data) => {
console.log(`Received message: ${data}`);
// Broadcast the message to all connected clients
io.emit('message', data);
});

// Handle disconnection
socket.on('disconnect', () => {
console.log('Client disconnected:', socket.id);
});
});

const PORT = process.env.PORT || 3000;


server.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`);
});

Code Example 2: Simple Socket.io Client


Place this file in the public/ directory (e.g., index.html ).

Backend (NodeJs) Developer Kit - Sample 46


<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Socket.io Client</title>
<script src="/socket.io/socket.io.js"></script>
<script>
document.addEventListener('DOMContentLoaded', () => {
const socket = io();

socket.on('connect', () => {
console.log('Connected to server via Socket.io');
});

socket.on('message', (data) => {


console.log('New message:', data);
const msgEl = document.createElement('p');
msgEl.innerText = data;
document.getElementById('messages').appendChild(msgEl);
});

// Send a message when the button is clicked


document.getElementById('sendBtn').addEventListener('click', () => {
const message = document.getElementById('messageInput').value;
socket.emit('message', message);
});
});
</script>
</head>
<body>
<h1>Real-Time Chat</h1>
<div id="messages"></div>
<input id="messageInput" type="text" placeholder="Type your message">
<button id="sendBtn">Send</button>

Backend (NodeJs) Developer Kit - Sample 47


</body>
</html>

Code Example 3: Using Rooms for Group Communication

// In server.js (within the io.on('connection') block)


io.on('connection', (socket) => {
console.log('New client connected:', socket.id);

// Join a room (e.g., "room1")


socket.join('room1');

// Listen for a message and broadcast it only to clients in "room1"


socket.on('roomMessage', (data) => {
io.to('room1').emit('message', data);
});

socket.on('disconnect', () => {
console.log('Client disconnected:', socket.id);
});
});

Part 9.2: Interview Questions & Code Challenges (15+)

Sample Interview Question 1


Q: How do you use namespaces in Socket.io, and why might you use them?
A:

Explanation: Namespaces allow you to separate concerns and create different


communication channels within the same Socket.io server.

Backend (NodeJs) Developer Kit - Sample 48


Code Example:

const adminNamespace = io.of('/admin');


adminNamespace.on('connection', (socket) => {
console.log('Admin client connected:', socket.id);
});

Sample Interview Question 2


Q: How do you test real-time events in your Node.js application?
A:

Explanation: Use the socket.io-client library in your test suite to simulate client
connections and assert events.

Code Example:

const ioClient = require('socket.io-client');


const socket = ioClient.connect('http://localhost:3000', { 'force new conn
ection': true });

socket.on('connect', () => {
console.log('Test client connected');
socket.emit('message', 'Test Message');
});

socket.on('message', (data) => {


console.log('Received message:', data);
socket.disconnect();
});

Backend (NodeJs) Developer Kit - Sample 49


10. DevOps & Deployment
Part 10.1: Concepts & Code Snippets
10.1.1 Containerization with Docker
Key Concepts:

Docker:
Containerization allows you to package your application and its dependencies
into a single image that runs consistently in any environment.

Dockerfile & Docker Compose:


A Dockerfile defines the image, and Docker Compose can orchestrate multiple
containers (e.g., application and database).

Code Example: Dockerfile for a Node.js App

# Use an official Node.js runtime as a base image


FROM node:16-alpine

# Set the working directory in the container


WORKDIR /app

# Copy package.json and package-lock.json


COPY package*.json ./

# Install dependencies
RUN npm install

# Copy the rest of the application code


COPY . .

# Expose the port the app runs on


EXPOSE 3000

Backend (NodeJs) Developer Kit - Sample 50


# Define the command to run the app
CMD ["npm", "start"]

Code Example: Docker Compose File

# docker-compose.yml
version: '3.8'
services:
app:
build: .
ports:
- "3000:3000"
environment:
- NODE_ENV=production
redis:
image: redis:alpine
ports:
- "6379:6379"

10.1.2 CI/CD Pipelines


Key Concepts:

CI/CD:
Continuous Integration and Continuous Deployment automate testing, building,
and deploying your application on code changes.

GitHub Actions / Jenkins:


Tools to define workflows for building and deploying Node.js apps.

Code Example: GitHub Actions Workflow

Backend (NodeJs) Developer Kit - Sample 51


# .github/workflows/nodejs-ci.yml
name: Node.js CI/CD

on: [push, pull_request]

jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [14.x, 16.x]
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node-version }}
- run: npm install
- run: npm test
- run: npm run build # if applicable
# Optionally, deploy steps can be added here

Code Example: Jenkins Pipeline (Jenkinsfile)

pipeline {
agent any
stages {
stage('Checkout') {
steps {
checkout scm
}
}

Backend (NodeJs) Developer Kit - Sample 52


stage('Install') {
steps {
sh 'npm install'
}
}
stage('Test') {
steps {
sh 'npm test'
}
}
stage('Build') {
steps {
sh 'npm run build'
}
}
stage('Deploy') {
steps {
// Example deploy command, modify as needed
sh 'scp -r . user@server:/path/to/deploy'
}
}
}
post {
always {
archiveArtifacts artifacts: '**/coverage/**/*', allowEmptyArchive: true
}
}
}

10.1.3 Logging & Monitoring


Key Concepts:

Winston:

Backend (NodeJs) Developer Kit - Sample 53


A popular logging library for Node.js, allowing configurable log levels and
transports (e.g., console, file).

PM2:
A process manager that helps you run, monitor, and manage Node.js
applications in production.

Code Example: Logging with Winston

// utils/logger.js
const { createLogger, format, transports } = require('winston');

const logger = createLogger({


level: 'info',
format: format.combine(
format.timestamp(),
format.printf(info => `[${info.timestamp}] ${info.level.toUpperCase()}: ${inf
o.message}`)
),
transports: [
new transports.Console(),
new transports.File({ filename: 'logs/app.log' })
]
});

module.exports = logger;

Code Example: PM2 Process Management

Create a file called ecosystem.config.js :

// ecosystem.config.js
module.exports = {
apps: [{

Backend (NodeJs) Developer Kit - Sample 54


name: 'node-app',
script: 'server.js',
instances: 2,
autorestart: true,
watch: false,
max_memory_restart: '500M',
env: {
NODE_ENV: 'development'
},
env_production: {
NODE_ENV: 'production'
}
}]
};

To start the app with PM2 in production:

pm2 start ecosystem.config.js --env production

Part 10.2: Interview Questions & Code Challenges


(15+)
Below are 15+ interview questions along with code snippet solutions focused on
DevOps and deployment for Node.js.

Sample Interview Question


Q: How do you ensure environment-specific configuration for your Node.js
application during deployment?
Answer:

Backend (NodeJs) Developer Kit - Sample 55


Explanation: Use environment variables and configuration files (e.g., .env
files) to manage settings for different environments.

Code Example:

// Accessing environment variable in Node.js


const port = process.env.PORT || 3000;

Machine Coding Rounds

Below is a list of 26 Machine Coding Challenges for Node.js Backend. Each


challenge includes a brief problem statement along with a sample code snippet
solution. You can use these examples to practice and build robust backend
features, as well as prepare for machine coding rounds during interviews.

1. Sample Question : In-Memory Key-Value Store API


Problem:
Implement an API to set, get, and delete key-value pairs stored in memory.
Solution:

// routes/kv.js
const express = require('express');
const router = express.Router();
const store = {};

router.post('/kv', (req, res) => {


const { key, value } = req.body;
store[key] = value;
res.status(201).json({ message: 'Key set successfully' });

Backend (NodeJs) Developer Kit - Sample 56


});

router.get('/kv/:key', (req, res) => {


const value = store[req.params.key];
if (value === undefined) return res.status(404).json({ error: 'Key not found'
});
res.status(200).json({ key: req.params.key, value });
});

router.delete('/kv/:key', (req, res) => {


if (!(req.params.key in store)) return res.status(404).json({ error: 'Key not fou
nd' });
delete store[req.params.key];
res.status(200).json({ message: 'Key deleted successfully' });
});

module.exports = router;

2. Sample Question : LRU Cache Implementation


Problem:
Design an LRU cache with get and put operations.
Solution:

// lruCache.js
class LRUCache {
constructor(capacity) {
this.capacity = capacity;
this.cache = new Map();
}

get(key) {

Backend (NodeJs) Developer Kit - Sample 57


if (!this.cache.has(key)) return -1;
const value = this.cache.get(key);
this.cache.delete(key);
this.cache.set(key, value);
return value;
}

put(key, value) {
if (this.cache.has(key)) {
this.cache.delete(key);
} else if (this.cache.size >= this.capacity) {
const firstKey = this.cache.keys().next().value;
this.cache.delete(firstKey);
}
this.cache.set(key, value);
}
}

const cache = new LRUCache(2);


cache.put(1, 1);
cache.put(2, 2);
console.log(cache.get(1)); // 1
cache.put(3, 3);
console.log(cache.get(2)); // -1

Backend (NodeJs) Developer Kit - Sample 58

You might also like