Node Interview - Intermediate
How do you debug a Node.js application?
Debugging a Node.js application can be done in several ways, depending on your environment, tools, and the complexity of the application.
i) Useconsole.log()Statementsconsole.log('User data:', user);ii) Use the Built-In Debugger
Node.js has a built-in debugger you can run withnode inspect app.js /* c – Continue execution n – Step to next line s – Step into a function o – Step out of a function repl – Enter interactive mode */To set a breakpoint in code
debugger;iii) Debug with Chrome DevTools
Start your app with the--inspectflag,node --inspect app.jsOpen Chrome and go to
chrome://inspect
Click “Open dedicated DevTools for Node”
You can now set breakpoints, step through code, inspect variables, and more.
iv) Use Logging Libraries
Use structured logging tools for better insights:winston, pino, debugv) Unit Testing + Debugging
Write tests using:
mocha, jest, avaRun tests in watch mode and debug failing ones.
vi) Monitor with External ToolsUse tools like,
PM2 (for production monitoring/debugging)
New Relic / Datadog (for profiling and performance debugging)
How do you handle errors in Node.js?
Handling errors in Node.js is critical for building robust, maintainable applications. Node.js provides several mechanisms for error handling, depending on whether the code is synchronous, asynchronous, uses promises, or streams.
i) General Principles
a) Always handle errors explicitly.b) Use consistent patterns across your application.
c) Avoid crashing the app for recoverable errors.
d) Use centralized error handling in web apps (like Express).
ii) Synchronous Code
Usetry...catchblockstry { const data = fs.readFileSync('file.txt'); console.log(data); } catch (err) { console.error('Error reading file:', err); }iii) Asynchronous Callbacks
Node uses the error-first callback pattern (
erras the first parameter)fs.readFile('file.txt', (err, data) => { if (err) { return console.error('Error reading file:', err); } console.log(data); });iv) Promises & Async/Await
Wrap your async code in
try...catchasync function readFile() { try { const data = await fs.promises.readFile('file.txt', 'utf-8'); console.log(data); } catch (err) { console.error('Error:', err.message); } }v) Express Error Handling
// Error-handling middleware app.use((err, req, res, next) => { console.error(err.stack); res.status(500).json({ error: 'Something went wrong!' }); }); // Example route with error app.get('/', (req, res, next) => { try { throw new Error('Oops!'); } catch (err) { next(err); } });vi) Global Error Handlers
Use as a last resort—don’t rely on them for control flow.process.on('uncaughtException', err => { console.error('Uncaught Exception:', err); process.exit(1); }); process.on('unhandledRejection', err => { console.error('Unhandled Rejection:', err); process.exit(1); });How do you handle file uploads in a Node.js application?
Handling file uploads in a Node.js application typically involves using middleware to parsemultipart/form-data, the encoding used by browsers for file uploads. The most common and robust solution is themultermiddleware when working with Express.js.
i) Install Required Packagesnpm install express multerii) Set Up
multerMiddlewareconst express = require('express'); const multer = require('multer'); const path = require('path'); const app = express(); // Configure storage const storage = multer.diskStorage({ destination: function (req, file, cb) { cb(null, 'uploads/'); // folder to store uploaded files }, filename: function (req, file, cb) { const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9); cb(null, uniqueSuffix + path.extname(file.originalname)); // preserve original extension } }); // Create the upload middleware const upload = multer({ storage: storage }); // Route to handle upload app.post('/upload', upload.single('myFile'), (req, res) => { console.log(req.file); // file info res.send('File uploaded successfully!'); }); app.listen(3000, () => console.log('Server running on port 3000'));iii) Test with an HTML Form
<form action="/upload" method="post" enctype="multipart/form-data"> <input type="file" name="myFile" /> <button type="submit">Upload</button> </form>iv) Storage Options in
multer
a) diskStorage - Store files locally on disk (as shown above)
b) memoryStorage - Store files in memory as Buffer objects
c) stream - Stream files to cloud storage or other APIsExplain the concept of callback functions in Node.js. Provide an example.
In Node.js, a callback function is a function passed as an argument to another function and is executed after that function completes. This is a fundamental concept in asynchronous programming, which Node.js heavily relies on—especially for I/O operations like file reading, database access, or HTTP requests.
i) Why Use Callbacks?
JavaScript in Node.js is non-blocking and single-threaded, so callbacks allow operations to run in the background and execute code once they're done—without stopping the rest of the program.
ii) Key Characteristics of Callbacks
They are passed as arguments to functions.They are invoked after an asynchronous operation completes.
Often follow the error-first pattern:
(err, result) => {}
iii) Reading a File Using a Callbackconst fs = require('fs'); fs.readFile('example.txt', 'utf8', (err, data) => { if (err) { return console.error('Error reading file:', err); } console.log('File contents:', data); });iv) Custom Callback Example
You can define your own functions that accept callbacks,function greetUser(name, callback) { console.log('Hello, ' + name); callback(); } greetUser('Alice', () => { console.log('This is a callback function!'); });v) Callback vs Promises (and Async/Await)
Callbacks are foundational, but can lead to callback hell if nested too deeplydoSomething(arg1, (err, result1) => { doSomethingElse(result1, (err, result2) => { andThenThis(result2, (err, result3) => { // ... hard to manage }); }); });What is the Node.js event loop? How does it work?
The Node.js Event Loop is the core mechanism that enables non-blocking, asynchronous I/O operations—even though JavaScript is single-threaded. It allows Node.js to perform many operations (like reading files, querying databases, or making HTTP requests) without blocking the main thread.
At its core, the event loop is a loop that monitors and processes asynchronous events in the background. It keeps the application running as long as there are callbacks to be executed.
i) How the Event Loop Works (High-Level Steps)
When Node.js runs your code, it uses the event loop to handle operations:a) Initialize: Executes your code (e.g., setting timers, reading files, registering callbacks).
b) Poll: Waits for incoming events (e.g., I/O, timers) and places them in the callback queue.
c) Callback Execution: Executes the callback associated with each event.
d) Repeat: Continues this process until no more work remains.
ii) Event Loop Phases (Simplified Overview)
The event loop has several phases that run in order,
a) Timers - ExecutessetTimeout()andsetInterval()callbacks
b) Pending Callbacks - Executes I/O callbacks deferred to the next loop
c) Idle / Prepare - Internal operations
d) Poll - Waits for new I/O events; executes I/O callbacks
e) Check - ExecutessetImmediate()callbacks
f) Close Callbacks - Executes callbacks likesocket.on('close', ...)
iii) Example to Illustrate TimingsetTimeout(() => console.log('timeout'), 0); setImmediate(() => console.log('immediate')); process.nextTick(() => console.log('nextTick')); console.log('sync'); // console.log('sync') runs first (synchronous). // process.nextTick() runs before the next phase of the event loop. // setTimeout(..., 0) and setImmediate() run in different phases (timers vs check).iv) Key Benefits
a) Non-blocking I/O: Efficiently handles thousands of connections.b) Lightweight: Fewer threads mean lower overhead.
c) Great for I/O-bound apps: APIs, chat servers, streaming apps, etc.
v) Limitationsa) CPU-bound operations block the event loop.
b) Heavy computation should be offloaded to worker threads or external services.
How do you read and write files in Node.js?
Reading and writing files in Node.js is done using the built-infs(File System) module. You can perform file operations both synchronously (blocking) and asynchronously (non-blocking).
Use async (non-blocking) for most apps—especially servers and APIs.
Use sync (blocking) for simple CLI tools, config loading, or during app startup.
Best Practises
a) Always handle errors usingtry...catchor error-first callbacks.b) Use the async versions to avoid blocking the event loop.
c) Use
path.join()to construct file paths reliably across platforms.d) Use the
fs.promisesAPI for cleaner async/await usage.Synchronous vs Asynchronous Operations
a) Synchronous (Blocking)Methods end in
Sync, e.g.,readFileSync,writeFileSync.Blocking: halts the entire program until the operation finishes.
Easier for scripting or startup tasks.
b) Asynchronous (Non-blocking)Do not block the event loop.
Use a callback or Promise to handle the result.
i) Reading Files - Asynchronously (non-blocking, recommended)const fs = require('fs'); fs.readFile('example.txt', 'utf8', (err, data) => { if (err) { return console.error('Error reading file:', err); } console.log('File content:', data); });ii) Reading Files - Synchronously (blocking)
const data = fs.readFileSync('example.txt', 'utf8'); console.log('File content:', data);iii) Reading Files - With Promises /
async/awaitconst fs = require('fs').promises; async function readFile() { try { const data = await fs.readFile('example.txt', 'utf8'); console.log('File content:', data); } catch (err) { console.error('Error:', err); } } readFile();iv) Writing Files - Asynchronously (non-blocking, recommended)
fs.writeFile('output.txt', 'Hello, world!', err => { if (err) return console.error('Error writing file:', err); console.log('File written successfully!'); });v) Writing Files - Synchronously (blocking)
fs.writeFileSync('output.txt', 'Hello, world!'); console.log('File written successfully!');vi) Reading Files - With Promises /
async/awaitconst fs = require('fs').promises; async function writeFile() { try { await fs.writeFile('output.txt', 'Hello, world!'); console.log('File written successfully!'); } catch (err) { console.error('Error writing file:', err); } } writeFile();What is Express.js? How does it simplify building web applications with Node.js?
Express.js is a minimal and flexible web framework for Node.js that provides powerful features to build web and mobile applications. It simplifies the process of creating server-side logic by abstracting much of the boilerplate code involved in handling HTTP requests, routing, middleware, and more.
Without Express, writing a web server in Node.js requires manually handling HTTP methods, headers, and routing logic using thehttpmodule. Express makes this much simpler and cleaner.
i) Key Features
a) Routing - Easily map URLs to handlers (GET, POST, etc.)
b) Middleware - Process requests (authentication, logging, body parsing, etc.)
c) Template Engine Support - Supports Pug, EJS, Handlebars for rendering dynamic HTML
d) Static Files - Serve static assets like CSS, JS, images
e) Error Handling - Centralized and structured error handling
f) REST API Support - Ideal for building RESTful APIs
ii) Basic Example// Install Express npm install express // Simple Server const express = require('express'); const app = express(); app.get('/', (req, res) => { res.send('Hello, World!'); }); app.listen(3000, () => { console.log('Server listening on port 3000'); });iii) Routing Example
app.get('/about', (req, res) => { res.send('About Page'); }); app.post('/submit', (req, res) => { res.send('Form Submitted'); });iv) Middleware Example
app.use(express.json()); // Parses JSON request bodies app.use((req, res, next) => { console.log(`${req.method} ${req.url}`); next(); // Pass control to the next handler });v) Error Handling Middleware
app.use((err, req, res, next) => { console.error(err.stack); res.status(500).send('Something went wrong!'); });vi) Benefits of Express.js
a) Great community and ecosystem
b) Easy learning curve for JavaScript/Node developers
c) Integrates well with databases and other Node.js libraries
d) Foundation for many popular frameworks (like NestJS, Sails)
How can you validate the input data in Node js Application?
In a Node.js application, validating input data is crucial for security, data integrity, and preventing bugs or injection attacks (like SQL or XSS). There are several ways to handle validation depending on your stack and needs.
i) Using a Validation Library (Recommended)// Popular Choice: Joi npm install joi // example const Joi = require('joi'); // Define schema const schema = Joi.object({ username: Joi.string().alphanum().min(3).max(30).required(), age: Joi.number().integer().min(18).required(), email: Joi.string().email().required() }); // Validate data const result = schema.validate({ username: 'JohnDoe', age: 25, email: 'john@example.com' }); if (result.error) { console.error('Validation error:', result.error.details); } else { console.log('Valid input!'); }ii) With Express Middleware
You can integrate Joi with Express to validate request bodiesconst express = require('express'); const Joi = require('joi'); const app = express(); app.use(express.json()); const userSchema = Joi.object({ name: Joi.string().required(), email: Joi.string().email().required() }); app.post('/user', (req, res) => { const { error } = userSchema.validate(req.body); if (error) { return res.status(400).json({ message: error.details[0].message }); } res.send('User data is valid'); });iii) Using
express-validator// install express-validator npm install express-validator // example const { body, validationResult } = require('express-validator'); app.post('/user', body('email').isEmail(), body('password').isLength({ min: 6 }), (req, res) => { const errors = validationResult(req); if (!errors.isEmpty()) { return res.status(400).json({ errors: errors.array() }); } res.send('Input is valid'); });iv) Manual Validation (Not Recommended for Complex Logic)
if (!req.body.name || typeof req.body.name !== 'string') { return res.status(400).send('Name is required and must be a string'); }v) Best Practices
a) Validate all user inputs: body, query, params, headers.
b) Use a schema-based library (like Joi) for maintainability.
c) Always return clear error messages to help with debugging (but avoid leaking sensitive info).
d) Sanitize inputs if needed (
express-validatoroffers sanitizers too).What is authentication? How is it implemented in Node.js applications?
Authentication is the process of verifying the identity of a user or system. In a Node.js application, it's used to confirm that a user is who they claim to be—usually by checking credentials like a username/password or a token.
i) Types of Authentication
a) Session-Based Authentication (typically with cookies)b) Token-Based Authentication (e.g. JSON Web Tokens – JWT)
c) OAuth / Third-party login (e.g. Google, Facebook)
d) API Key Authentication
ii) Common Authentication Implementation in Node.js
a) Password hashing -bcryptorargon2
b) JWT tokens -jsonwebtoken
c) Middleware -passportor custom
d) Sessions -express-session
iii) JWT Authentication – Common Approach
Install Dependenciesnpm install express jsonwebtoken bcryptjsUser Login Flow
const express = require('express'); const jwt = require('jsonwebtoken'); const bcrypt = require('bcryptjs'); const app = express(); app.use(express.json()); const users = [{ id: 1, username: 'admin', password: '$2a$10$...' }]; // hashed passwords app.post('/login', async (req, res) => { const { username, password } = req.body; const user = users.find(u => u.username === username); if (!user) return res.status(400).send('User not found'); const valid = await bcrypt.compare(password, user.password); if (!valid) return res.status(401).send('Invalid password'); const token = jwt.sign({ id: user.id }, 'secretKey', { expiresIn: '1h' }); res.json({ token }); });Protect Routes with Middleware
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, 'secretKey', (err, user) => { if (err) return res.sendStatus(403); // Invalid token req.user = user; next(); }); } // Protected route app.get('/dashboard', authenticateToken, (req, res) => { res.send('Protected dashboard content'); });Best Practices -
a) Hash passwords before storing (never store plain text).
b) Store secrets securely (e.g. in
.envfiles).c) Use HTTPS to protect token transmission.
d) Implement token expiration and refresh where appropriate.
e) Validate input data before authenticating.
iv) Session-Based Auth (with express-session)npm install express-sessionconst session = require('express-session'); app.use(session({ secret: 'yourSecret', resave: false, saveUninitialized: true, cookie: { secure: false } // use true with HTTPS }));Sessions store user identity on the server (e.g., in memory, Redis), and send a cookie to the browser.
How do you handle CORS (Cross-Origin Resource Sharing) in a Node.js application?
Handling CORS (Cross-Origin Resource Sharing) in a Node.js application is essential when your front-end and back-end are hosted on different origins (domains, ports, or protocols). CORS is a security feature enforced by browsers that restricts web pages from making requests to a different origin than the one that served the web page.
CORS allows a server to specify who can access its resources and which methods are allowed. If not handled correctly, the browser will block cross-origin requests from the client.
i) Install thecorspackagenpm install corsii) Basic Usage with Express
const express = require('express'); const cors = require('cors'); const app = express(); app.use(cors()); // Enable CORS for all origins app.get('/data', (req, res) => { res.json({ message: 'This is CORS-enabled for all origins!' }); }); app.listen(3000, () => console.log('Server running on port 3000'));iii) Restrict CORS to Specific Origin
const corsOptions = { origin: 'https://example.com', // only allow this domain methods: ['GET', 'POST'], allowedHeaders: ['Content-Type', 'Authorization'] }; app.use(cors(corsOptions));iv) Enable CORS for a Single Route
app.get('/public', cors(), (req, res) => { res.json({ message: 'CORS-enabled route' }); });v) CORS with Credentials (cookies, auth headers)
const corsOptions = { origin: 'http://localhost:3000', credentials: true }; app.use(cors(corsOptions));Ensure your client-side request also includes,
fetch('http://localhost:5000/api', { credentials: 'include' });vi) Best Practices
a) Use
cors()middleware for ease and flexibility.b) Be specific in production: avoid
*forAccess-Control-Allow-Origin.c) Enable credentials only when needed and configure
originaccordingly.d) Be cautious with sensitive routes or APIs.
Explain the concept of WebSockets and their Use in Node.js Applications
WebSockets are a communication protocol that provides full-duplex, bidirectional communication between the client (e.g., browser) and server over a single, long-lived TCP connection.Unlike HTTP (which is request-response-based), WebSockets allow real-time communication without repeatedly reestablishing connections or polling.
Node.js is a great platform for WebSockets due to its non-blocking, event-driven nature.
Common Libraries -a)
ws– lightweight WebSocket implementation.
b)socket.io– higher-level library, abstracts over WebSocket with fallback support.
i) Key Features of WebSocketsb) Low latency
c) Real-time updates
d) Uses
ws://orwss://(secure WebSocket)
ii) When to Use WebSocketsa) Real-time chat apps
b) Live notifications
c) Real-time games
d) Collaborative tools (e.g., Google Docs)
e) Live stock/price updates
iii) Usingws(WebSocket)
a) Installationnpm install wsb) Server (node js)
const WebSocket = require('ws'); const wss = new WebSocket.Server({ port: 8080 }); wss.on('connection', ws => { console.log('Client connected'); ws.on('message', message => { console.log('Received:', message); ws.send(`Server echo: ${message}`); }); ws.on('close', () => console.log('Client disconnected')); });c) Client (Browser)
<script> const socket = new WebSocket('ws://localhost:8080'); socket.onopen = () => { socket.send('Hello Server!'); }; socket.onmessage = event => { console.log('From server:', event.data); }; </script>iv) Using
socket.io(More Feature-Rich)
a) Installationnpm install socket.iob) Server
const http = require('http').createServer(); const io = require('socket.io')(http); io.on('connection', socket => { console.log('User connected'); socket.on('chat message', msg => { io.emit('chat message', msg); }); socket.on('disconnect', () => console.log('User disconnected')); }); http.listen(3000, () => console.log('Listening on *:3000'));c) Client
<script src="/socket.io/socket.io.js"></script> <script> const socket = io('http://localhost:3000'); socket.on('chat message', msg => { console.log('Message:', msg); }); socket.emit('chat message', 'Hello from client'); </script>What is Event Emitter in Node.js?
In Node.js, the EventEmitter is a core module that enables an event-driven architecture. It allows objects (like servers, streams, etc.) to emit named events and for other parts of the code to listen and react to those events.This is fundamental to how Node.js handles asynchronous operations efficiently.
i) How It Works
TheEventEmitterclass is part of the built-ineventsmodule.const EventEmitter = require('events'); const emitter = new EventEmitter();ii) Basic Example: Emitting and Listening
// Register a listener emitter.on('greet', (name) => { console.log(`Hello, ${name}!`); }); // Emit the event emitter.emit('greet', 'Alice');iii) Key Methods of EventEmitter
a) on(event, listener) - Registers a listener (can run multiple times)
b) once(event, listener) - Runs the listener only once
c) emit(event, [args]) - Triggers the event, optionally passing data
d) removeListener() - Removes a specific listener
e) removeAllListeners() - Removes all listeners for an event
f) listenerCount(event) - Returns number of listeners for an event
iv) Common Use Cases in Node.js
a) HTTP servers (req.on('data'),res.on('finish'))b) Streams (
readable.on('data'))c) File system watcher
d) Custom app-level events
What are streams and what are types of streams available in Node.js?
In Node.js, streams are powerful abstract interfaces for working with streaming data—data that isn’t available all at once, but instead arrives in chunks over time (e.g., reading a large file, streaming audio/video, receiving HTTP responses).Using streams helps improve performance, memory usage, and scalability in data-heavy applications.
i) What Are Streams?A stream is like a data pipeline where you can read from a source or write to a destination piece by piece, instead of loading everything into memory at once.
ii) Four Main Types of Streams
a) Readable - Can be read fromfs.createReadStream(), HTTP request
b) Writable - Can be written tofs.createWriteStream(), HTTP response
c) Duplex - Can be read from and written to
TCP socket (net.Socket)
d) Transform - Duplex stream that can modify data as it passes through
zlib.createGzip()
iii) Example: Readable Streamconst fs = require('fs'); const readable = fs.createReadStream('large-file.txt'); readable.on('data', chunk => { console.log('Received chunk:', chunk.length); }); readable.on('end', () => { console.log('Finished reading file.'); });iv) Example: Writable Stream
const fs = require('fs'); const writable = fs.createWriteStream('output.txt'); writable.write('Hello, '); writable.write('world!'); writable.end(); // Signals end of writingv) Example: Piping Readable → Writable
const fs = require('fs'); const readStream = fs.createReadStream('input.txt'); const writeStream = fs.createWriteStream('output.txt'); readStream.pipe(writeStream); // Transfers contentvi) Example: Transform Stream (e.g., Compression)
const fs = require('fs'); const zlib = require('zlib'); const gzip = zlib.createGzip(); const input = fs.createReadStream('file.txt'); const output = fs.createWriteStream('file.txt.gz'); input.pipe(gzip).pipe(output);vii) Benefits of Streams
a) Memory efficient: Handle large files/data in small chunks.
b) Faster: Start processing before the full data is available.
c) Composable: Chain multiple streams together using
.pipe().What is Piping in Node?
Piping in Node.js is a mechanism used with streams to connect the output of one stream directly into the input of another. This allows you to chain operations and pass data efficiently from one stream to another without manually handling data events.
Piping lets you transfer data from a readable stream to a writable stream automatically and efficiently.
Piping is a method to connect streams and transfer data.Use
.pipe()to link a readable stream to a writable (or transform) stream.It’s commonly used for file I/O, compression, HTTP responses, and data processing.
i) Example: Reading from a File and Writing to Anotherconst fs = require('fs'); const readStream = fs.createReadStream('input.txt'); const writeStream = fs.createWriteStream('output.txt'); // Pipe the read stream into the write stream readStream.pipe(writeStream);This reads
input.txtin chunks and writes them tooutput.txtwithout loading the entire file into memory.
ii) Chaining Multiple Pipes
You can pipe through multiple transform streams to modify data.const fs = require('fs'); const zlib = require('zlib'); const gzip = zlib.createGzip(); const read = fs.createReadStream('file.txt'); const write = fs.createWriteStream('file.txt.gz'); read.pipe(gzip).pipe(write); // Compresses the fileiii) Benefits of Piping
a) Memory Efficient – handles data in chunks.
b) Readable & Writable – stream data from one place to another.
c) Simplifies code – avoids manual
.on('data')and.write()handling.d) Easy to compose – chain multiple streams together (e.g., transform, compress, log).
What is the difference between setImmediate() and setTimeout()?
The difference betweensetImmediate()andsetTimeout()in Node.js lies in when they execute their callbacks in the event loop. Although both schedule asynchronous operations, their timing behavior is slightly different.
i) setTimeout(callback, 0)
Executes the callback after a minimum delay of 0 milliseconds.The callback is scheduled in the timers phase of the event loop.
Actual execution depends on the system timer granularity and current event loop load.
setTimeout(() => { console.log('setTimeout'); }, 0);ii) setImmediate(callback)
Executes the callback immediately after the I/O events are processed.The callback is scheduled in the check phase of the event loop.
Typically runs before
setTimeout(..., 0)if both are called in the same phase.setImmediate(() => { console.log('setImmediate'); });What is Swagger and How it helps to maintain the ReSTful API in Node js?
Swagger is a toolset and specification for describing, documenting, testing, and visualizing RESTful APIs. It is now part of the OpenAPI Specification (OAS).i) In Node.js, Swagger helps developers
a) Define API structure in a standardized way.
b) Automatically generate interactive API documentation.
c) Validate request/response schemas.
d) Improve team collaboration and client integration.
ii) Key Benefits of Swagger in Node.js
i) API documentation - Generates live, interactive docs (like Swagger UI)
ii) API validation - Validates input/output based on schema
iii) Client SDK generation - Auto-generates client SDKs in various languages
iv) Testing support - Allows testing APIs directly from the docs
v) Improves communication - Easy for frontend/backend teams or 3rd parties to understand APIs
iii) Install Required Packagesnpm install swagger-jsdoc swagger-ui-expressiv) Set Up Swagger in
app.jsorserver.jsconst express = require('express'); const swaggerUi = require('swagger-ui-express'); const swaggerJsdoc = require('swagger-jsdoc'); const app = express(); const swaggerDefinition = { openapi: '3.0.0', info: { title: 'Example API', version: '1.0.0', description: 'A simple Express API with Swagger', }, servers: [ { url: 'http://localhost:3000', }, ], }; const options = { swaggerDefinition, apis: ['./routes/*.js'], // Path to the API docs }; const swaggerSpec = swaggerJsdoc(options); app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpec));v) Document Your Routes with JSDoc-style Comments
/** * @swagger * /hello: * get: * summary: Returns a greeting * responses: * 200: * description: A simple message */ app.get('/hello', (req, res) => { res.send('Hello Swagger!'); });vi) Access Swagger UI
Navigate to,
http://localhost:3000/api-docsYou’ll see a live, interactive documentation page for your API.What is Redis and How it helps to cache the API resposne in Node js?
Redis (Remote Dictionary Server) is a fast, in-memory key-value data store often used as:Cache, Database, Message broker
In Node.js, Redis is commonly used to cache API responses to improve performance and reduce load on databases or third-party APIs.
i) Why Use Redis for Caching?
a) Extremely Fast - Keeps data in memory (not disk) for ultra-low latency
b) Avoids Repetition - Prevents repeated database or API calls
c) Reduces Latency - Speeds up response time for frequently requested data
d) TTL Support - Auto-expire cached data using Time-To-Live
e) Scalable - Works well with distributed systems
ii) How to Use Redis for Caching in a Node.js API
a) Install Redis and Redis ClientInstall Redis on your system (or use a service like Redis Cloud).
Then install the Node.js client,
npm install redisb) Connect to Redis
const redis = require('redis'); const client = redis.createClient(); client.connect().then(() => console.log('Redis connected'));c) Cache API Response Example
const express = require('express'); const app = express(); const axios = require('axios'); app.get('/weather/:city', async (req, res) => { const { city } = req.params; const cacheKey = `weather:${city}`; // 1. Check cache const cached = await client.get(cacheKey); if (cached) { return res.json({ source: 'cache', data: JSON.parse(cached) }); } // 2. If not cached, fetch from API const apiResponse = await axios.get(`https://api.weatherapi.com/v1/current.json?key=YOUR_KEY&q=${city}`); // 3. Store response in Redis for 1 hour await client.setEx(cacheKey, 3600, JSON.stringify(apiResponse.data)); res.json({ source: 'API', data: apiResponse.data }); });iii) Common Use Cases of Redis Caching in Node.js
a) API rate limitingb) Session storage
c) Frequently accessed DB queries
d) Third-party API responses (e.g., weather, stock prices)
e) Full-page or partial-page caching
How do you manage dependencies in a Node.js project to prevent compatibility issues or security vulnerabilities?
Managing dependencies in a Node.js project is critical for stability, security, and maintainability. Here's how you can do it effectively,
i) Usepackage.jsonandpackage-lock.json
a)package.jsondefines project dependencies, versions, scripts, and metadata.b)
package-lock.jsonlocks the exact versions of installed packages to ensure consistent installs across environments.
Best Practices -a) Never delete
package-lock.jsonb) Commit it to version control (Git)
ii) Use Semantic Versioning Wisely// In package.json "express": "^4.17.1" /* ^ allows minor and patch upgrades ~ allows only patch upgrades No prefix = locked version */a) Be cautious with
^and~—unexpected updates may introduce breaking changes.b) Use
npm install <pkg>@versionto install specific versions if needed.
iii) Audit for Security Vulnerabilitiesnpm audita) Scans dependencies for known vulnerabilities.
b) Lists severity (Low, Moderate, High, Critical).
npm audit fixiv) Regularly Update Dependencies
Use tools like:npm outdatedornpm-check-updates(ncu)npx npm-check-updates -u npm installv) Remove Unused or Obsolete Packages
npm prunevi) Use a
.npmrcFile for Config// To lock down behavior save-exact=true // This will save packages without the ^ symbol, e.g., "express": "4.17.1".vii) Use CI/CD for Testing Compatibility
a) Run
npm ciin CI pipelines for clean, deterministic installs.b) Use automated tests to catch issues from dependency updates.
viii) Consider Using Dependency Management Tools
a) Dependabot (GitHub) – automatically creates PRs for outdated or vulnerable packages.b) Snyk – finds and fixes vulnerabilities.
c) Renovate – manages version updates.
Explain the OS module in Node.js?
Theosmodule in Node.js is a built-in module that provides a way to interact with the operating system. It allows you to retrieve system-related information such as the hostname, memory, CPU details, network interfaces, and more.You don’t need to install it — it's part of Node.js core.
const os = require('os');Example
const os = require('os'); console.log('Hostname:', os.hostname()); // Returns the hostname of the OS console.log('Platform:', os.platform()); // Returns the platform (e.g., 'linux', 'win32') console.log('CPU Architecture:', os.arch()); // Returns CPU architecture (e.g., 'x64') console.log('Total Memory (MB):', os.totalmem() / 1024 / 1024); // Total system memory (in bytes) console.log('Free Memory (MB):', os.freemem() / 1024 / 1024); // Free system memory (in bytes) console.log('Uptime (minutes):', os.uptime() / 60); // System uptime in seconds console.log('User Info:', os.userInfo()); // Info about the currently logged-in userUse Cases in Real Applications
a) System monitoring dashboards
b) Logging OS info in backend apps
c) Performance tuning and diagnostics
d) Load balancing based on CPU/memory
e) Temp file storage (via
os.tmpdir())What is a Node Inspector?
Node Inspector is a debugging tool for Node.js applications that allows you to debug your code using Chrome DevTools or other browser-based interfaces. It provides a visual way to:
a) Set breakpoints
b) Step through code
c) Inspect variables and call stack
d) Monitor memory usage
It connects to the V8 Inspector Protocol, which Node.js supports natively.
i) Why Use Node Inspector?a) Visual Debugging - Easier than console.log debugging
b) Step Execution - Pause, resume, step into/over functions
c) Variable Inspection - See scope, values, closures in real time
d) Live Code Editing - Modify code while paused (in Chrome DevTools)
e) Heap & CPU Profiling - Useful for performance tuning
ii) How to Use Node Inspector (Built-In Since Node.js v6.3+)
a) Run your script with the--inspectflagnode --inspect index.jsb) Open Chrome and Go to
chrome://inspectThen click “Open dedicated DevTools for Node”.
You’ll now see Chrome DevTools connected to your Node.js app.
c) Set Breakpoints and DebugUse the Sources tab to browse your code
Set breakpoints by clicking line numbers
Use the Console, Scope, and Call Stack panels for full control