1. Initialize the Project
Begin by creating a new project directory and initializing it with npm init
:
mkdir blog-backend
cd blog-backend
npm init -y
This will create a package.json
file for your project. Afterward, install the necessary dependencies with:
npm install express body-parser dotenv mongoose cookie-parser morgan nodemon bcrypt jsonwebtoken express-validator express-async-handler slugify
These packages include everything we need for creating and securing routes, handling requests, interacting with MongoDB, and managing cookies.
2. Project Structure
The basic structure of your project should look like this:
blog-backend/
├── config/
│ └── dbConnect.js
├── routes/
│ ├── authRoute.js
│ ├── productRoute.js
│ └── blogRoute.js
├── index.js
├── .env
└── package.json
config/dbConnect.js
: For setting up the MongoDB connection.routes/
: Directory for handling different routes (auth, product, blog).index.js
: The main entry point for your application.
3. Database Connection
In the config/dbConnect.js
file, establish a connection to MongoDB using Mongoose:
// dbconnect.js
import dotenv from "dotenv";
import mongoose from "mongoose";
dotenv.config();
export const dbConnect = async () => {
try {
console.log(
"🚀 ~ dbConnect ~ process.env.MONGO_URI:",
process.env.MONGO_URI
);
await mongoose.connect(process.env.MONGO_URI, {
useNewUrlParser: true,
useUnifiedTopology: true,
});
console.log("MongoDB connected successfully");
} catch (error) {
console.error("MongoDB connection failed");
}
};
Make sure to create a
.env
file and add your MongoDB connection string:PORT=8000 MONGO_URI=mongodb://localhost:27017/myDatabase
4. Setting Up the Server
In the index.js
file, we will set up the server using Express.js:
// index.js
import express from "express";
import dotenv from "dotenv";
import bodyParser from "body-parser";
import cookieParser from "cookie-parser";
import { dbConnect } from "./config/dbconnect.js";
import { authRouter } from "./routes/authRoute.js";
dotenv.config();
const app = express();
const port = process.env.PORT || 3000;
// Body parser is used to parse the incoming request bodies in a middleware before you handle it.
app.use(cookieParser());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.listen(port, () => {
console.log(`Server is running on port ${port}`);
});
app.use("/api/auth", authRouter);
dbConnect();
Morgan logs HTTP requests.
Body-parser allows us to parse incoming requests in JSON and URL-encoded formats.
Cookie-parser enables us to work with cookies.
5. Creating Model
Create a model with name userModel.js which willl create a table in mongoDB where we will perform the crud operation from controller
// userModel.js
import mongoose from "mongoose";
import bcrypt from "bcryptjs";
var userSchema = new mongoose.Schema(
{
firstname: {
type: String,
required: true,
trim: true,
min: 3,
max: 20,
},
lastname: {
type: String,
required: true,
trim: true,
min: 3,
max: 20,
},
username: {
type: String,
required: true,
trim: true,
unique: true,
index: true,
lowercase: true,
},
email: {
type: String,
required: true,
trim: true,
unique: true,
lowercase: true,
},
password: {
type: String,
required: true,
},
},
{
timestamps: true,
}
);
// Yo code chai password lai encrypt garna lai
userSchema.pre("save", async function (next) {
if (!this.isModified("password")) {
next();
}
const salt = await bcrypt.genSaltSync(10);
this.password = await bcrypt.hash(this.password, salt);
});
// password match vaxa ki nai vanera check garna
userSchema.methods.isPasswordMatched = async function (enteredPassword) {
return await bcrypt.compare(enteredPassword, this.password);
};
export default mongoose.model("User", userSchema);
6. Creating Controller
Create the route files for authentication, products, and blogs. Each route file will contain the Express routing logic for handling requests.
Example for controller/UserController.js
:
// UserController.js
import { validationResult } from "express-validator";
import User from "../models/userModel.js";
import expressAsyncHandler from "express-async-handler";
import { generateToken } from "../config/jwtToken.js";
export const createUser = async (req, res) => {
try {
const errors = validationResult(req);
console.log("🚀 ~ createUser ~ req:", req.body);
if (!errors.isEmpty()) {
return res.status(400).json({
errors: errors.array(),
message: "validation error",
success: false,
});
}
//check if user already exists
const isExist = await User.findOne({
email: req.body.email,
});
console.log("🚀 ~ createUser ~ isExist:", isExist);
if (isExist) {
return res.status(400).json({
message: "User already exists",
success: false,
});
}
const user = await User.create(req.body);
return res.status(201).json({
message: "User created successfully",
success: true,
data: user,
});
} catch (error) {
console.error(
"🚀 ~ file: UserController.js ~ line 13 ~ createUser ~ error",
error
);
}
};
export const updateUser = expressAsyncHandler(async (req, res) => {
try {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({
errors: errors.array(),
message: "validation error",
success: false,
});
}
const user = await User.findByIdAndUpdate(req.params.id, req.body, {
new: true,
});
return res.status(200).json({
message: "User updated successfully",
success: true,
data: user,
});
} catch (errro) {
return res.status(400).json({
message: "User not found",
success: false,
});
}
});
export const getAllUsers = expressAsyncHandler(async (req, res) => {
try {
const users = await User.find();
return res.status(200).json({
message: "Users fetched successfully",
success: true,
data: users,
});
} catch (error) {
console.error("🚀 ~ getAllUsers ~ error", error);
return res.status(500).json({
message: "Server error",
success: false,
});
}
});
export const deleteUser = expressAsyncHandler(async (req, res) => {
try {
const user = await User.findById(req.params.id);
if (!user) {
return res.status(404).json({
message: "User not found",
success: false,
});
}
await User.findByIdAndDelete(req.params.id);
return res.status(200).json({
message: "User deleted successfully",
success: true,
});
} catch (error) {
console.error("🚀 ~ deleteUser ~ error", error);
return res.status(500).json({
message: "Server error",
success: false,
});
}
});
// login user
export const userLogin = expressAsyncHandler(async (req, res) => {
const { email, password } = req.body;
// findUser variable include all the information of that user with that email.
const findUser = await User.findOne({ email });
const accessToken = generateToken(findUser._id);
// ava store garam token lai cookie ma
res.cookie("accessToken", accessToken, {
httpOnly: true,
maxAge: 72 * 60 * 60 * 1000,
});
if (findUser && (await findUser.isPasswordMatched(password))) {
// res.json(findUser);
res.json({
// ?. syntax is called optional chaining introduced on ecma script in 2020
_id: findUser?._id,
firstname: findUser?.firstname,
lastname: findUser?.lastname,
email: findUser?.email,
mobile: findUser?.mobile,
token: generateToken(findUser?._id),
});
} else {
throw new Error("Invalid Credentials");
}
});
7. Creating Routes
Create the route files for authentication, products, and blogs. Each route file will contain the Express routing logic for handling requests.
Example for routes/authRoute.js
:
//authRoute.js
import express from "express";
import { createUser } from "../controller/UserController.js";
const router = express.Router();
router.post("/createUser", createUser);
export { router as authRouter };
You can follow a similar structure for the productRoute.js
and blogRoute.js
.
8. Testing the Server
Create a middleware to authenticate the user. It check if the current user trying to perform the operation is autenticated user not.
// authMiddleware.js
import User from "../models/userModel.js";
import jwt from "jsonwebtoken";
import expressAsyncHandler from "express-async-handler";
export const authMiddleware = expressAsyncHandler(async (req, res, next) => {
let token;
if (req?.headers?.authorization?.startsWith("Bearer")) {
token = req.headers.authorization.split(" ")[1];
if (token) {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
const user = await User.findById(decoded?.id);
req.user = user;
next();
}
} else {
return res.status(401).json({
message: "Not authorized token, Please login again",
success: false,
});
}
});
9. Testing the Server
To test if your server is running, start it by running:
npm run server
If everything is set up correctly, you should see:
Server is listening on port http://localhost:5000