MERNStackDeveloperKit(Sample)
MERNStackDeveloperKit(Sample)
Sample
Hello and welcome! I'm Parikh Jain, and I'm excited to share with you the ultimate
guide to become a MERN Stack 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
5. Database Integration
9. Real-Time Communication
Frontend Development
HTML & CSS Concepts With Interview Questions & Code Snippets
Target Audience
Aspiring Node.js Developers: Beginners who want to learn Node.js
fundamentals and build a strong foundation in backend development.
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?
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.
Full-Stack Integration:
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.
Important Concepts
Node.js Runtime:
npm is used to install, manage, and update Node.js packages and libraries.
Visit the Node.js official website and download the LTS version.
bash
Copy
node -v
npm -v
Important Concepts
Project Metadata:
npm Initialization:
Use npm init (or npm init -y for default settings) to generate the package.json file.
bash
Copy
npm init -y
Sample package.json
json
Copy
{
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:
"scripts": {
"start": "node server.js",
"dev": "nodemon server.js",
"test": "jest"
}
3. Running Scripts:
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.
Code Snippets
1. VS Code Settings ( .vscode/settings.json ):
{
"editor.formatOnSave": true,
"eslint.alwaysShowStatus": true,
"gitlens.advanced.messages": {
"suppressShowKeyBindingsNotice": true}
}
2. Git Setup:
git init
node_modules/
.env
git add .
node -v
npm -v
Expected Output: Version numbers for both Node.js and npm confirm proper
installation.
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> .
Run Script:
npm start
Express Instance:
Middleware:
// server.js
const express = require('express');
const app = express();
const PORT = process.env.PORT || 3000;
Routing:
Middleware Functions:
Functions that intercept and process requests before passing them on to the
next handler.
module.exports = router;
// server.js (continued)
const greetingRoute = require('./routes/greeting');
app.use('/api', greetingRoute);
// 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:
Request Logging:
Use libraries like Morgan to log HTTP requests automatically.
// 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;
Answer:
router.use() applies middleware only to the routes defined within that router.
Code Example:
// Router-specific middleware
const router = express.Router();
router.use((req, res, next) => {
console.log('Router-specific middleware');
next();
});
Code Example:
// In routes/users.js
const express = require('express');
const router = express.Router();
module.exports = router;
// In server.js
const usersRouter = require('./routes/users');
app.use('/api/users', usersRouter);
HTTP Methods:
Status Codes:
Use proper HTTP status codes (e.g., 200, 201, 400, 404, 500) to communicate
the outcome of API requests.
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.
module.exports = router;
// server.js
const express = require('express');
const app = express();
const PORT = process.env.PORT || 3000;
// Global error handler (optional, see next section for more on error handling)
app.use((err, req, res, next) => {
console.error('Error:', err.stack);
Answer:
Code Example:
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() });
}
Code Example:
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.
Mongoose:
// db.js
const mongoose = require('mongoose');
module.exports = connectDB;
Schema Definition:
Define the structure of your documents using Mongoose schemas.
Models:
Create models based on schemas to interact with the corresponding
MongoDB collections.
// models/User.js
const mongoose = require('mongoose');
Express Integration:
// routes/users.js
const express = require('express');
const router = express.Router();
const User = require('../models/User');
// 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' });
// 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 }
);
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;
Middleware (Hooks):
Pre/post hooks in Mongoose to perform actions before or after operations.
// models/Post.js
const mongoose = require('mongoose');
In the User model, you can reference posts (if needed) or simply populate posts in
your queries:
Code Example:
(Refer to the pagination endpoint snippet in Part 5.1.4)
User.find().skip(skip).limit(limit)
.then(users => res.json(users))
.catch(err => next(err));
Code Example:
UserSchema.pre('save', function(next) {
console.log('Before saving user:', this);
next();
});
jsonwebtoken Library:
A popular Node.js library for generating and verifying JWTs.
// routes/auth.js
const express = require('express');
const jwt = require('jsonwebtoken');
const router = express.Router();
const secret = process.env.JWT_SECRET || 'your_jwt_secret';
module.exports = router;
// middleware/authenticate.js
const jwt = require('jsonwebtoken');
const secret = process.env.JWT_SECRET || 'your_jwt_secret';
module.exports = authenticateToken;
// routes/protected.js
const express = require('express');
const router = express.Router();
const authenticateToken = require('../middleware/authenticate');
bcrypt:
A widely used library for hashing and comparing passwords securely.
// utils/hashPassword.js
const bcrypt = require('bcrypt');
// Example usage:
hashPassword('myPlainPassword')
.then(hashed => console.log('Hashed password:', hashed))
.catch(err => console.error(err));
module.exports = hashPassword;
// utils/verifyPassword.js
const bcrypt = require('bcrypt');
// 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;
// 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';
// 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 };
// 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' });
module.exports = router;
Code Example:
function generateToken(user) {
return jwt.sign({ id: user.id, username: user.username }, secret, { expiresI
n: '1h' });
}
Code Example:
Interview Question 4
Q: How do you protect a route so that only authenticated users can access it?
Answer:
Code Example:
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.
// utils/math.js
function add(a, b) {
return a + b;
}
module.exports = { add };
// tests/math.test.js
npm test
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.
// server.js
const express = require('express');
const app = express();
const PORT = process.env.PORT || 3000;
app.use(express.json());
module.exports = app;
// tests/api.test.js
const request = require('supertest');
const app = require('../server');
TDD:
Write tests before writing the actual code. This ensures that your code meets
the specified requirements.
Cycle:
Red (fail) → Green (pass) → Refactor.
// tests/counter.test.js
const { increment } = require('../utils/counter');
test('increment should add 1 to the number', () => {
expect(increment(1)).toBe(2);
});
// utils/counter.js
function increment(n) {
return n + 1;
}
module.exports = { increment };
CI Pipelines:
Automate tests on every push/commit using tools like GitHub Actions or
Jenkins.
# .github/workflows/nodejs.yml
name: Node.js CI
Code Example:
Answer:
Use Jest’s built-in mocking functions to simulate external modules.
Code Example:
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.
// redisClient.js
const redis = require('redis');
const client = redis.createClient({ host: '127.0.0.1', port: 6379 });
client.on('connect', () => {
console.log('Connected to Redis');
});
module.exports = client;
// routes/data.js
const express = require('express');
const router = express.Router();
const redisClient = require('../redisClient');
module.exports = router;
Lean Queries:
In MongoDB/Mongoose, using .lean() returns plain JavaScript objects instead
of Mongoose documents, reducing overhead.
Code Profiling:
Use tools like Node.js built-in profiler or external tools (e.g., Clinic.js) to
identify bottlenecks.
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.
1. Installation:
// middleware/rateLimiter.js
const rateLimit = require('express-rate-limit');
module.exports = limiter;
Code Example:
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:
Handling Connections:
// server.js
const express = require('express');
const http = require('http');
const socketIo = require('socket.io');
<!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');
});
Code Example:
Explanation: Use the socket.io-client library in your test suite to simulate client
connections and assert events.
Code Example:
socket.on('connect', () => {
console.log('Test client connected');
socket.emit('message', 'Test Message');
});
Docker:
Containerization allows you to package your application and its dependencies
into a single image that runs consistently in any environment.
# Install dependencies
RUN npm install
# docker-compose.yml
version: '3.8'
services:
app:
build: .
ports:
- "3000:3000"
environment:
- NODE_ENV=production
CI/CD:
Continuous Integration and Continuous Deployment automate testing, building,
and deploying your application on code changes.
# .github/workflows/nodejs-ci.yml
name: Node.js CI/CD
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:
pipeline {
agent any
stages {
stage('Checkout') {
steps {
checkout scm
}
}
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
Winston:
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.
// utils/logger.js
const { createLogger, format, transports } = require('winston');
module.exports = logger;
// ecosystem.config.js
module.exports = {
apps: [{
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'
}
}]
};
Code Example:
Solution:
// routes/kv.js
const express = require('express');
const router = express.Router();
const store = {};
module.exports = router;
// lruCache.js
class LRUCache {
constructor(capacity) {
this.capacity = capacity;
this.cache = new Map();
}
get(key) {
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);
}
}
Frontend Development
HTML & CSS Interview Questions With Solutions &
Code Snippets (25 Questions)
Sample Question 1: How do you create a responsive navigation bar using HTML
& CSS? (Intermediate)
Answer:
A responsive navigation bar typically uses semantic <nav> elements, lists for menu
items, and media queries to adapt styles for different screen sizes. Techniques
like Flexbox are often employed to align items.
Code Example:
<nav class="navbar">
<ul>
<li><a href="#">Home</a></li>
<li><a href="#">About</a></li>
<li><a href="#">Services</a></li>
<li><a href="#">Contact</a></li>
</ul>
.navbar ul {
display: flex;
list-style: none;
padding: 0;
}
.navbar li {
margin-right: 20px;
}
@media (max-width: 600px) {
.navbar ul {
flex-direction: column;
}
.navbar li {
margin: 10px 0;
}
}
Sample Question 2: How does CSS specificity work when combining selectors,
and how can you override styles defined with high specificity, such as inline
styles? (Hard)
Answer:
CSS specificity is calculated based on the number of ID selectors, class selectors,
and element selectors used. Inline styles have the highest specificity. To override
styles with high specificity, you can use the !important flag or create a selector with
higher specificity, though this should be done sparingly.
Code Example:
// Capturing phase
document.getElementById("child").addEventListener("click", () => {
function memoize(fn) {
const cache = {};
return function(...args) {
const key = JSON.stringify(args);
if (cache[key]) {
return cache[key];
}
const result = fn(...args);
cache[key] = result;
return result;
}
}
const factorial = memoize(function(n) {
if (n === 0) return 1;
return n * factorial(n - 1);
});
console.log(factorial(5)); // 120
function* numberGenerator() {
let num = 0;
while (true) {
yield num++;
}
}
const gen = numberGenerator();
console.log(gen.next().value); // 0
console.log(gen.next().value); // 1
const myIterable = {
data: [1, 2, 3],
[Symbol.iterator]() {
let index = 0;
const data = this.data;
return {
next() {
2. Sample Question: How does the React Context API work for managing
global state? (Intermediate)
Answer:
The Context API provides a way to pass data through the component tree
without having to pass props down manually at every level. It’s useful for
global data like themes, user authentication, or language settings.
Code Example:
2. Question: How does lazy loading work in Angular and why is it beneficial?
(Intermediate)
Answer: Lazy loading loads feature modules only when needed, reducing the
initial bundle size and improving application startup performance.
Code Example:
1. Sample Question: How do you pass data from a parent component to a child
component in Vue? (Intermediate)
Answer:
Data is passed from a parent to a child using props. The child component
declares the props it expects, and the parent binds data to those props.
Code Example:
// Parent Component
// In a Vue component
const AsyncComponent = () => import('./components/AsyncComponent.vu
e');
export default {
components: {
AsyncComponent
},
template: `<AsyncComponent />`
}
// .eslintrc.json
{
"env": {
"browser": true,
"node": true,
"es6": true},
"extends": "eslint:recommended",
"rules": {
"semi": ["error", "always"],
"quotes": ["error", "single"]
}
}
// main.js
const worker = new Worker('worker.js');
worker.postMessage('Start processing');
worker.onmessage = function(event) {
console.log('Result:', event.data);
};
// worker.js
onmessage = function(event) {
// Perform heavy computation here
postMessage('Processing complete');
Answer: Optimize animations by using CSS transforms and opacity (which are
GPU-accelerated), avoiding layout changes during animations, and preferring CSS
animations over JavaScript when possible.
Code Example:
@keyframes fadeIn {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
.animated {
animation: fadeIn 0.5s ease-in-out;
}
1
. Countdown Timer
Problem:
Implement a countdown timer that counts down to a specified future date.
Solution:
HTML:
JavaScript:
──────────────────────────────
Infinite Scrolling with Lazy Loading
Plain Implementation:
HTML:
<div id="infinite-scroll-container">
<ul id="item-list"></ul>
</div>
CSS:
#infinite-scroll-container {
height: 400px;
overflow-y: auto;
border: 1px solid #ccc;
padding: 10px;
}
#item-list li {
margin-bottom: 20px;
}
#item-list img {
width: 100%;
display: block;
opacity: 0;
transition: opacity 0.5s ease-in;
}
#item-list img.visible {
opacity: 1;
}
let page = 1;
const loadItems = async () => {
// Simulated API call (replace with actual API)
for (let i = 0; i < 10; i++) {
const li = document.createElement('li');
li.innerHTML = `
<h4>Item ${page * 10 + i}</h4>
<img data-src="https://via.placeholder.com/400x200?text=Item+${page
* 10 + i}" alt="Item Image">
`;
list.appendChild(li);
}
lazyLoadImages();
page++;
};
// Initial load
loadItems();
React Implementation:
// InfiniteScroll.jsx
import React, { useState, useEffect, useRef } from 'react';
function InfiniteScroll() {
const [items, setItems] = useState([]);
const [page, setPage] = useState(1);
const containerRef = useRef(null);
useEffect(() => {
loadItems();
}, []);
return (
<divid="infinite-scroll-container"
ref={containerRef}
style={{ height: '400px', overflowY: 'auto', border: '1px solid #ccc', padding: '
onScroll={handleScroll}
>
Sample 1
. Closure Example
Demonstrates closure for data encapsulation.
function counter() {
let count = 0;
return function() {
count++;
return count;
};
}
Sample 2
. Mapping Over an Array in React
Generates a list from an array.
──────────────────────────────