Backend Setup Documentation
Project Structure:
1️Creating and Opening the Project Folder
Follow these steps to set up your backend project in VS Code:
1. Create a project folder:
2. Navigate into the folder:
3. Open the folder in VS Code:
2️Initializing the Backend Project
Now, initialize your Node.js backend:
Run this command in the terminal to create a package.json file:
3️Installing Required Packages
Install the necessary dependencies for your backend:
Run this in VS Code terminal:
4️Configuring Execution Policy (For Windows Users)
If you face permission issues when running scripts, use the following command in
PowerShell (Run as Administrator):
5️Running the Backend Server
To start your backend, use this command in the VS Code terminal:
Testing Your API in Postman
Test Adding a User (POST Request)
Steps:
1. Open Postman.
2. Select POST as the request method.
3. In the URL field, enter: http://localhost:5000/api/users/addUser
4. Navigate to the Headers section and add:
5. Content-Type: application/json
6. Go to the Body tab and select raw.
7. Choose JSON from the dropdown menu.
8. Copy and paste the following JSON data:
9. Click Send.
10. Expected Response:
Test Fetching All Users (GET Request)
Steps:
1. Open Postman.
2. Select GET as the request method.
3. In the URL field, enter: http://localhost:5000/api/users/getUser
4. Click Send.
5. Expected Response:
Here’s the Product.js schema file, similar to your User.js file:
📌 Product.js (Schema)
const mongoose = require('mongoose');
const ProductSchema = mongoose.Schema({
name: {
type: String,
required: true
},
category: {
type: String,
required: true
},
price: {
type: Number,
required: true
},
stock: {
type: Number,
required: true,
default: 0
},
description: {
type: String
}
});
module.exports = mongoose.model('Product', ProductSchema);
📌 routes/Product.js (Routes for Product API)
const express = require('express');
const router = express.Router();
const Product = require('../schema/Product');
// ✅ Add a Product
router.post('/addProduct', async (req, res) => {
try {
const { name, category, price, stock, description } = req.body;
if (!name || !category || !price) {
return res.status(400).json({ error: "Name, category, and price are required." });
}
const newProduct = new Product({
name,
category,
price,
stock,
description
});
await newProduct.save();
res.status(201).json(newProduct);
} catch (error) {
console.error("Error adding product:", error);
res.status(500).json({ error: "Internal server error" });
}
});
// ✅ Get All Products
router.get('/getProducts', async (req, res) => {
try {
const products = await Product.find();
res.json(products);
} catch (err) {
console.error("Error fetching products:", err);
res.status(500).json({ error: err.message });
}
});
module.exports = router;
📌 Add This to index.js
Make sure to include the Product.js routes in index.js:
const productRoutes = require('./routes/Product');
app.use('/api/products', productRoutes);
📌 How to Test in Postman?
1️Add a Product (POST Request)
URL: http://localhost:5000/api/products/addProduct
Method: POST
Body (raw JSON):
{
"name": "Laptop",
"category": "Electronics",
"price": 1000,
"stock": 10,
"description": "A high-end gaming laptop."
}
Expected Response: 201 Created with the product data.
2️Get All Products (GET Request)
URL: http://localhost:5000/api/products/getProducts
Method: GET
Expected Response:
[
{
"_id": "65123456789abcdef",
"name": "Laptop",
"category": "Electronics",
"price": 1000,
"stock": 10,
"description": "A high-end gaming laptop."
}
]
Get all users
router.get('/getUser', async (req, res) => {
try {
const users = await User.find(); // ✅ Fixed syntax
res.json(users);
} catch (err) {
console.error("Error fetching users:", err);
res.status(500).json({ error: err.message }); // ✅ Return error message
}
});
URL: http://localhost:5000/users/getUsers
Get user by id
router.get('/get/:id',async(req,res)=>{
const id= req.params.id;
try{
const user = await User.findById(id);
if(!user)
{
res.json({message:"User not found"});
}
res.json(user);
}
catch(err)
{
res.json({message:err})
}
})
URL: http://localhost:5000/users/get/67d26e908eaac970285787ff
Update data in db
router.put('/update/:id', async (req, res) => {
const id = req.params.id;
try {
const { name, city, age, email, password } = req.body;
const user = await User.findById(id);
if (!user) {
res.json({ message: "User not Found" });
if (name) {
user.name = name;
if (city) {
user.city = city;
if (age) {
user.age = age;
if (email) {
user.email = email;
if (password) {
user.password= password;
await user.save();
res.json({message:"user updated"})
}
catch (error) {
res.status(500).json({ error: error.message });
});
URL: http://localhost:5000/users/update/67d2668affafee06aed16be7
🔥 Base Route in index.js:
app.use('/users', userRoutes); → Sets the base route for userRoutes.
All routes in userRoutes are appended to /users.
Example:
router.put('/update/:id', ...) → Becomes /users/update/:id.
Full URL: http://localhost:5000/users/update/:id.
✅ Correct: http://localhost:5000/users/update/:id.
❌ Incorrect: http://localhost:5000/update/:id.
✅ Key Points for Modifying Data in DB
⚙️1. Keep Existing Values When Updating
Only provided fields are updated.
To retain existing values:
o Fetch the existing document.
o Merge new data with it.
o Save the merged document.
🔥 2. Use async/await with Asynchronous Operations
Asynchronous operations (like DB queries) return Promises, which take time to
resolve.
Use async/await to handle them properly.
Without await, your code may move on before the database operation is completed,
leading to unexpected results or incomplete updates.
3. Sync vs. Async Execution
Synchronous Execution:
o Executes line by line.
o Waits for each line to complete before moving to the next.
o Downside: Causes delays if database operations take time.
Asynchronous Execution:
o Uses async/await or Promises.
o Waits for DB operations to finish before moving on.
o Prevents blocking the main thread, making your app faster.
🔒 4. Update Only Provided Fields Without Overwriting Others
To avoid overwriting unspecified fields with null or undefined, use a spread operator
or a merging technique.
const user = await User.findById(id);
if (!user) return res.status(404).json({ message: "User not found" });
const updates = {
name: req.body.name || user.name,
city: req.body.city || user.city,
age: req.body.age || user.age,
email: req.body.email || user.email,
password: req.body.password ? await bcrypt.hash(req.body.password, 10) : user.password
};
const updatedUser = await User.findByIdAndUpdate(id, updates, { new: true });
res.status(200).json({ message: "User updated", user: updatedUser });
✅ This ensures:
Only specified fields are updated.
Unspecified fields retain their original values.
🚀 5. Use Proper Error Handling
Always wrap DB operations in try-catch blocks to handle errors gracefully.
Return appropriate status codes:
o 200: Success.
o 400: Bad request (invalid input).
o 404: Not found.
o 500: Server error.
REST API VS JQL
JQL is not like REST API, where you need to send a request and wait for a response for
every operation.
🔥 Key Differences:
JQL (Jira Query Language) →
o Works like a database query within Jira.
o No need for multiple requests.
o You can run a single query to fetch filtered results.
o Example:
project = "Marketing" AND status = "In Progress"
o Retrieves all matching Jira issues instantly.
REST API →
o Uses HTTP requests (GET, POST, etc.) to interact with a server.
o Requires multiple requests for complex data retrieval.
o Example:
GET /rest/api/3/search?jql=project=Marketing&status=In Progress
o Needs repeated requests for different operations.
✅ Key Takeaway:
JQL → Direct querying within Jira → Faster and simpler for Jira-specific searches.
REST API → Request-response model → Needed for external integrations and
multi-step operations.
Hard Delete vs. Soft Delete
✅ Hard Delete → Removes the record completely from the database.
URL: http://localhost:5000/users/delete/67d2668affafee06aed16be7
router.delete('/hard-delete/:id', async (req, res) => {
const id = req.params.id;
try {
const user = await User.findByIdAndDelete(id); // Permanently deletes
if (!user) {
res.json({ message: "User not found" });
} else {
res.json({ message: "User hard deleted" });
}
} catch (err) {
res.json({ message: err });
}
});
✅ Soft Delete → Marks the record as deleted by updating a field (e.g., isDeleted: true), but
keeps the data in the database.
router.delete('/soft-delete/:id', async (req, res) => {
const id = req.params.id;
try {
const user = await User.findByIdAndUpdate(id, { isDeleted: true }); // Marks as deleted
if (!user) {
res.json({ message: "User not found" });
} else {
res.json({ message: "User soft deleted" });
}
} catch (err) {
res.json({ message: err });
}
});
👉 Soft Delete Advantage: You can restore the record later by setting isDeleted: false.
👉 Hard Delete Risk: Data is lost permanently and cannot be recovered.
Login without encryption
router.post('/login', async(req,res)=>{
const{email,password}=req.body;
const user = await User.findOne({email,password});
if(user) { res.json({message:"login successful"}); }
else
{res.json({message:"login failed"}); }
}
)
Login with encryption
Add user:
router.post('/addUser', async (req, res) => {
try {
const { name, city, age, email, password } = req.body;
// Hash the password
const hashedPassword = await bcrypt.hash(password, 10);
// Create new user object
const newUser = new User({
name,
city,
age,
email,
password: hashedPassword
});
// Save user to database
await newUser.save();
res.json(newUser);
} catch (error) {
res.status(500).json({ error: "Failed to add user", details: error.message });
}
});
Add a User (POST Request)
URL: http://localhost:5000/users/addUser
Method: POST
Body (raw JSON):
Install package
npm install bcrypt
login code:
router.post('/login', async (req, res) => {
try {
// Extract email and password from the request body
const { email, password } = req.body;
// Find the user in the database by email
const user = await User.findOne({ email });
// Check if user exists and compare the entered password with the stored hashed
password
if (user && (await bcrypt.compare(password, user.password))) {
res.json({ message: "Login successful" }); // Send success response if password
matches
} else {
res.json({ message: "Login failed" }); // Send failure response if user not found or
password is incorrect
}
} catch (error) {
res.status(500).json({ error: "Internal Server Error" }); // Handle any unexpected errors
}
});
Login (POST Request)
URL: http://localhost:5000/users/login
Method: POST
Body (raw JSON):
Get Product by User ID
Schema/Product.js
createdAt: {
type: Date,
default: Date.now
},
createdBy: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
required: true
}
Add CreatedBy in Product (POST Request)
Routes/Prouduct.js
router.post('/addProduct', async (req, res) => {
try {
const { name, category, price, stock, description, createdBy } = req.body;
if (!name || !category || !price|| !createdBy) {
return res.status(400).json({ error: "Name, category, and price are required." });
}
const newProduct = new Product({
name,
category,
price,
stock,
description,
createdBy
});
await newProduct.save();
res.status(201).json(newProduct);
} catch (error) {
console.error("Error adding product:", error);
res.status(500).json({ error: "Internal server error" });
}
});
Add product (POST Request)
URL: http://localhost:5000/products/addProduct
Method: POST
Body (raw JSON):
{
"name": "Wireless Mouse",
"category": "Electronics",
"price": 1500,
"stock": 50,
"description": "A high-precision wireless mouse with ergonomic design.",
"createdBy": "67e4d7509938436cce68cb97"
}
Note: The "createdBy" field should contain a valid ObjectId from the Users
collection. Ensure that the provided ObjectId (e.g., "67e4d7509938436cce68cb97")
exists in the Users database before associating it with a product.
Get Product by User ID (GET Request)
router.get('/get/:userId', async (req, res) => {
const userId = req.params.userId;
//The endpoint is '/get/:userId', where :userId is a dynamic parameter.
try {
const product = await Product.find({createdBy: userId}).populate('createdBy', 'name
email');
if (product.length === 0) {
return res.status(404).json({ message: "Product not found" });
} else {
res.json(product);
}
} catch (err) {
res.status(500).json({ error: err.message });
}
});
Add product (POST Request)
URL: http://localhost:5000/products/get/67e4d7509938436cce68cb97
Method: POST
Note: The URL should include the same userId that was used in the "createdBy" field
when adding the product. Ensure that 67e4d7509938436cce68cb97 is a valid ObjectId from
the Users collection to retrieve products created by that user.
React
1. DOM, React Virtual DOM, and How It Works
DOM (Document Object Model): A structured representation of HTML elements.
React Virtual DOM: A lightweight copy of the actual DOM that React uses to
optimize rendering.
How It Works:
o React updates the Virtual DOM first.
o It compares changes using a diffing algorithm.
o Only the changed elements are updated in the actual DOM, improving
performance.
2. Pages Built in App.js Rendered as Root by a Single Page in index.js
Entry Point (index.js):
o index.js is the main entry file of a React application.
o It imports App.js and renders it inside the <div id="root"> in index.html using
ReactDOM.createRoot().render().
Rendering Flow:
1. The browser loads index.html, which contains an empty <div id="root">.
2. index.js executes, importing App.js and injecting it inside the root element.
3. App.js acts as the main container and organizes different components (header,
footer, pages, etc.).
4. If React Router is used, App.js dynamically switches between components
without reloading the entire page, maintaining the Single Page Application
(SPA) behavior.
5. Any updates in App.js are reflected in the UI without a full page reload
3. Git vs GitHub
Git: A version control system for tracking changes in code.
GitHub: A cloud-based hosting service for Git repositories.
Git helps in managing versions, while GitHub provides a platform to collaborate and
store repositories online.
4. MongoDB Compass vs Atlas
MongoDB Compass: A GUI tool to interact with local MongoDB databases.
MongoDB Atlas: A cloud-based database service to host and manage MongoDB
online.
Compass is used for local databases, while Atlas provides a managed cloud solution.
5. Why Not Push node_modules or .env to Git
node_modules: Contains installed dependencies, which can be reinstalled using
package.json.
.env: Stores environment variables (e.g., API keys, credentials) and should be kept
private for security reasons.
Both are excluded using .gitignore.
6. React Setup Commands
Creating a React App:
E:\backend>npx create-react-app frontend
Starting the Development Server:
cd frontend
npm start
Additional Commands:
npm start → Starts the development server.
npm run build → Bundles the app into static files for production.
npm test → Starts the test runner.
npm run eject → Removes Create React App setup (irreversible action).
7. React Project Structure
node_modules → Contains installed dependencies.
public → Stores static assets like images.
src → Contains application logic and components.
src/App.js → Main component file.
App.css, index.css → Stylesheets for the application.
.gitignore → Specifies files to be ignored by Git.
package.json → Stores project dependencies and scripts.
8. Port 3000
The default port for running a React development server.
Can be changed in .env or by specifying PORT=xxxx npm start.
9. React Router Setup:
Instead of traditional navigation where clicking a link reloads a new HTML file,
React Router intercepts navigation and dynamically updates the UI.
Routes are defined inside App.js (or a separate Routes.js file), using
<BrowserRouter> and <Routes>.
10. Component-Based Navigation:
When a user navigates, React updates only the relevant component instead of
reloading the entire page.
The URL changes, but React swaps components efficiently inside the existing page
structure without fetching a new HTML document.
11. Why It Feels Like Multiple Pages?
Each "page" is just a component mapped to a route (e.g., /about loads <About />).
The browser history is updated dynamically, allowing users to navigate back and
forward using the browser buttons—just like a multi-page website but without
reloading.
Vite: Instant React Build
npm create vite@latest my-app → Creates a React project with Vite, a fast build tool.
Unlike create-react-app, Vite doesn’t generate node_modules immediately.
Cross-platform: Works on Windows, macOS, and Linux.
Super fast: Uses ES module imports instead of bundling everything upfront.
Installing Dependencies (node_modules)
Since Vite doesn't create node_modules by default, run:
npm install
o This installs all dependencies and generates the node_modules folder.
Vite's Default Port
Runs on port 5173 instead of 3000 (used by create-react-app).
Can be changed in vite.config.js.
create-react-app vs. Vite
Feature create-react-app (CRA) Vite
Build Speed Slow (Webpack) Fast (ES Modules)
Initial Setup Creates everything upfront Creates minimal setup
node_modules Created? Yes, immediately No, until npm install
Default Dev Port 3000 5173
Hot Reloading Slower Instant
Best For Large projects with Webpack Fast development & modern projects
Start your app
npm run dev
Why npm start Doesn't Work?
Vite does not use react-scripts, so there is no "start" script in your package.json.
Instead, Vite uses "dev" to run the development server.
Class vs Functional Components in React
In React, components are the building blocks of the UI. There are two main types:
1️ Class Components
Defined using ES6 classes.
Must extend React.Component.
Use render() to return JSX.
Can have state and lifecycle methods (componentDidMount, componentDidUpdate,
etc.).
Example: Class Component
import React, { Component } from 'react';
class Welcome extends Component {
render() {
return <h1>Hello, {this.props.name}!</h1>;
}
}
export default Welcome;
2️ Functional Components
Defined as a JavaScript function.
Do not use this.
Before React 16.8, functional components were stateless.
With hooks (useState, useEffect), they can now manage state and side effects.
Example: Functional Component
import React from 'react';
function Welcome(props) {
return <h1>Hello, {props.name}!</h1>;
}
export default Welcome;
Key Differences: Class vs Functional Components
Feature Class Component Functional Component
Syntax Uses ES6 class Uses function
State Management Uses this.state Uses useState hook
Lifecycle Methods Uses componentDidMount, etc. Uses useEffect
Performance Slightly slower (due to class instantiation) Faster
Preferred? ❌ No (outdated) ✅ Yes (modern React)
Important Points to Remember
1️ All functions can be components, but not all components are functions.
Functional components are functions that return JSX.
Class components are not functions.
2️ React components must return a single parent element.
Solution:
Wrap content inside a <div>.
Use an empty tag (<>...</>) to avoid unnecessary divs.
Example:
function App() {
return (
<>
<h1>Welcome</h1>
<p>This is a functional component.</p>
</>
);
}
Why Functional Components Do Not Use this?
In class components, this is required to access props and state, but in functional
components, it is not needed.
1️ Class Components Require this
In class components, we must use this.props and this.state:
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}!</h1>; // Using `this`
}
}
Since class components are objects, this refers to the current instance.
Forgetting to bind this in event handlers can cause errors.
2️ Functional Components Do Not Need this
Functional components directly receive props as arguments:
function Welcome(props) {
return <h1>Hello, {props.name}!</h1>; // No `this` needed
}
Functional components are just functions, so this is not required.
They use hooks like useState instead of this.state.
Key Benefit: No this Means Simpler Code
No need for .bind(this).
Easier to read and maintain.
Avoids common "Cannot read property of undefined" errors.
Props vs State in React
Both props and state are used to manage data in a React app, but they serve different
purposes.
1️ Props (Short for "Properties")
🔹 Props are used to pass data from a parent component to a child component.
🔹 They are read-only (immutable), meaning a child component cannot modify props.
🔹 Think of props as arguments passed to a function.
Example: Passing Props from Parent to Child
function Greeting(props) {
return <h1>Hello, {props.name}!</h1>;
}
function App() {
return <Greeting name="Dakshin Priya" />;
}
👉 Here, name="Dakshin Priya" is passed as a prop to the Greeting component.
2️ State
🔹 State is used to manage dynamic data inside a component.
🔹 Unlike props, state can be changed inside the component using setState (class
components) or useState (functional components).
🔹 When state updates, the component re-renders automatically.
Example: Using State in a Functional Component
import { useState } from "react";
function Counter() {
const [count, setCount] = useState(0); // Initial state is 0
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increase</button>
</div>
);
}
👉 Clicking the button updates the state (count), causing the component to re-render.
🔍 Key Differences Between Props and State
Feature Props State
Who controls it? Parent component Component itself
Can it be changed? ❌ No (Read-only) ✅ Yes (Mutable)
Purpose Pass data to child components Manage internal data
Triggers re-render? No Yes
Different Ways to Handle Props in Home.jsx
1. Destructuring in Function Parameter (Recommended)
function Home({ user: { name, age, location } }) {
return (
<>
<h1>Home</h1>
<h1>Welcome {name}</h1>
<h2>{age}</h2>
<h2>{location}</h2>
</>
);
}
✅ Clean & concise
❌ Can break if user is undefined
2. Standard Props Usage (Without Destructuring)
import React from 'react';
function Home(props){
return(
<>
<h1>Home</h1>
<h1>Welcome {props.user.name}</h1>
<h2>{props.user.age}</h2>
<h2>{props.user.location}</h2>
</>
)
}
export default Home;
✅ Beginner-friendly, avoids errors
❌ Repetitive (props.user.name)
3. Destructuring Inside Function Body
import React from 'react';
function Home({ user }) {
return (
<>
<h1>Home</h1>
<h1>Welcome {user.name}</h1>
<h2>{user.age}</h2>
<h2>{user.location}</h2>
</>
);
}
export default Home;
✅ Flexible & allows validation
❌ Slightly more lines of code
App.js
import React from 'react';
import Home from './Home';
function App(){
const user={
name:'Dakshin Priya,Mckalya',
age: 20,
location: 'India'
}
return(
<>
<h1>Hello</h1>
<Home user={user}/>
</>
)
}
Using the Spread Operator with Props in Home.jsx
The spread operator (...) allows us to pass all properties of an object as individual props,
making the code more flexible.
1. Using Spread Operator When Passing Props
function App() {
const user = {
name: 'Dakshin Priya, Mckalya',
age: 20,
location: 'India'
};
Return(
<>
<Home {...user}/>
</>
)
// Spreads user properties as separate props
}
✅ Simplifies prop passing
❌ Can make it harder to track all passed props
2. Using Spread Operator in Function Parameters
import React from 'react';
function Home({ name, age, location }) {
return (
<>
<h1>Home</h1>
<h1>Welcome {name}</h1>
<h2>Age: {age}</h2>
<h2>Location: {location}</h2>
</>
);
}
export default Home;
import React, { useState, useEffect } from 'react';
const Home = () => {
// Count state
const [count, setCount] = useState(0);
// Theme state
const [theme, setTheme] = useState('light');
// Function to increment the count
const handleIncrement = () => {
setCount(count => count + 1);
};
// Function to decrement the count, reset to 10 if it reaches 0
const handleDecrement = () => {
if (count === 0) {
setCount(10);
} else {
setCount(count => count - 1);
}
};
// Toggle theme function
const toggleTheme = () => {
setTheme(theme => (theme === 'light' ? 'dark' : 'light'));
};
// Preventing infinite loop - set count to 100 only once on component mount
useEffect(() => {
// Set the initial count to 100
setCount(100);
// Fetch product data from a fake store API
//https://fakestoreapi.com/
const data = fetch('https://fakestoreapi.com/products');
// Handle the response: convert it to JSON and log the data to console
data
.then((res) => res.json()) // Convert the response to JSON format
.then((data) => console.log(data)); // Log the fetched data to the console
// Log to indicate that useEffect has been triggered
console.log('useEffect called');
}, []);
// Empty dependency array means this runs only once
// Dynamic styles based on theme
const styles = {
backgroundColor: theme === 'light' ? 'white' : 'black',
color: theme === 'light' ? 'black' : 'white',
textAlign: 'center',
marginTop: '50px',
padding: '20px',
minHeight: '100vh'
};
return (
<div style={styles}>
<h1>Count: {count}</h1>
<button onClick={handleIncrement}>Increment</button>
<button onClick={handleDecrement} style={{ marginLeft: '10px' }}>
Decrement
</button>
<div style={{ marginTop: '20px' }}>
<button onClick={toggleTheme}>Toggle Theme</button>
</div>
</div>
);
};
export default Home;
🔸 CORS
CORS (Cross-Origin Resource Sharing) is NOT used to define the backend API.
Instead, it allows the frontend (from a different origin/domain/port) to access the
backend API without getting blocked by the browser.
✅ Example:
React app (http://localhost:3000) tries to access Express API (http://localhost:5000) —
browser blocks it unless CORS is enabled.
const cors = require('cors');
app.use(cors()); // Allows cross-origin requests
🔸 Axios
Axios is used on the frontend (React) to send HTTP requests (GET, POST, etc.) to
backend APIs.
✅ Example:
axios.post('http://localhost:5000/feedback', formData); // Submits data
axios.get('http://localhost:5000/feedback'); // Fetches data