How to create a blog API using node, express and MongoDB

I'm a backend engineer and a proficient technical writer

INTRODUCTION
The main purpose of this blogging API is to allow users to create a blog post using different endpoints with different HTTP methods, whereby users can create, read, update and delete the blog post. In this article I will be explaining in detail how a reader of this article can make use of this blogging API whether authenticated or not because not all endpoints can be accessed by an unauthorized user, the blog post created and the response sent to users are in JSON content, as we go further we’ll throw more light on this.
PREREQUISITES
I assume that the reader of this article should have a little knowledge of how express and MongoDB work, if not please take a little time to check the resources described below and have the following installed ;
MongoDB Atlas/Compass
Nodejs
vsCode
postman
SETTING UP LOCALLY
To set up the project locally forking this repo and clone via this link, then you to your command line whichever one you are using power shell, git bash or command prompt to cd <folder>, mkdir<new folder>, cd<new folder> then npm init -y to create npm packages and you can also use npm init alone but with this, you have to start filling some little form about your new project, but using the npm init-y will give default settings.
Then npm install or you npm install all the modules needed, this will save all the dependencies in the package.json file.

RESOURCES DESCRIPTION
This app was built using nodejs and some external libraries like express, MongoDB, mongoose, Joi, jsonwebtoken, bcrypt, passport, nodemailer, passport-jwt and helmet as you go reading this article I will give a little explanation on how all this library work and how they are useful to this project.
Express
Express are top-level function code module used in nodejs for sending requests and receiving responses from users to the backend of an app, express has so many applications which are very useful to modern-day web development you can check express to know more about it.
MongoDB
MongoDB is a database used for saving user JSON data, MongoDB has an offline deployment called MongoDB compass and an online deployment called MongoDB Atlas, we use the offline deployment most for testing our app because it does require an internet connection and MongoDB uses for real working app deployment because data are more safely kept in the MongoDB database you check more on MongoDB.
Mongoose
Mongoose's function in our modern-day web development is to save created JSON data to our database it also does the function of saving any changes made to the data in the database, the mongoose is used for creating schemas for data sent to the database and it also used for validation of data and creating models you can check for more on mongoose.
Joi
Joi is a third-party library used for validating user input before saving it to the database, joi provides a well-customized error message when user input is wrong to know more about joi you can check JOI.
Jsonwebtoken (jwt)
Jsonwebtoken is a third-party library used for signing user input such as first name, last name and username, but not all user input is signed with just what I mean here is input like password and confirm password are not signed by jwt because the token sent by jwt can be easily decrypted and vital information will be licked to external users or intruders you can check more on JWT.
Bcrypt
Bcrypt is used for hashing user input mostly passwords and it is also for comparing hashed user input before validating the user. You can check more on Bcrypt
PASSPORT
Passports use the concept of strategies to authenticate requests, in this blog API we used the JWT strategy as means of authentication, we used it as middleware for all authenticated routes, you can check the passport out here.
Passport-Jwt
With this module called passport-jwt passport uses the JSON web token strategy to authenticate users passport-jwt takes in some options which are the jwtFromRequest, secrets and a call back function with a payload. you can check out for passport-jwt .
With all these modules we can successfully build a blog API by installing node and installing all the external libraries mentioned above using node package manager (npm) for example npm install <module>.
LET'S START BUILDING OUR BLOG API
We start building our blog API with "npm init" to have a package.JSON file to save all the external modules, then we start creating folders and files.
The setting of the App and Database
The first file we created was the app.js file in our app.js we have our express required, some middleware like body-parser,express-rate-limiter, and helmet and we also have our routes and error handling middleware then we export our app.
const express = require("express");
const passport = require("passport");
const bodyparser = require("body-parser");
const rateLimiter = require("express-rate-limit");
const auth_router = require("./Routes/authRouter");
const blogRouter = require("./Routes/blogRouter");
const userRouter = require("./Routes/userRouter");
require("dotenv").config;
const app = express();
app.use(bodyparser.json());
// RATE LIMITTER
const limiter = rateLimiter({
windowMs: 0.5 * 60 * 1000,
max: 4,
standardHeaders: true,
legacyHeaders: false,
});
app.use(limiter);
//INITIALIZING PASSPORT
app.use(passport.initialize());
// require("./Utils/passport");
//routes
app.use("/", auth_router);
app.use("/blogs", blogRouter);
app.use("/users", userRouter);
app.get("/", (req, res) => {
res.send("welcome to homepage");
});
//Error handling middleware
app.use((err, req, res, next) => {
const status = err.status || 500;
const message = err.message.message || "server error!!!!!";
return res.status(status).json({ status: "somthing broke", message });
});
module.exports = app;
Next is creating a server.js file where we need our server connections, here we need to require mongoose and dotenv. After creating our server we need to need to install nodemon (npm install -g nodemon) to help us restart our server anytime we make any changes and save, to run nodemon we can run nodemon server.js or npm run start:dev.
require("dotenv").config();
const connectToMongoDB = require("./blogDb");
const app = require("./app");
const PORT = process.env.PORT;
connectToMongoDB();
app.listen(PORT, () => {
console.log("Listening on port", PORT);
});
Then we create a blogDB.js file where we connect to our database, mongoose and dotenv are required for this connection. In this file, we have a "connectToMogoDb" function that writes to the console if the connection is successful and an error message if the connection is not successful.
const mongoose = require("mongoose");
require("dotenv").config();
const CONNECTION_URL = process.env.BLOG_CONNECTION_URL;
function connectToMongoDB() {
mongoose.connect(CONNECTION_URL);
mongoose.connection.on("connected", () => {
console.log("connected to Mongodb succesfully");
});
mongoose.connection.on("error", (err) => {
console.log(err);
console.log("An error occured");
});
}
module.exports = connectToMongoDB;
In the image below we have the success message when the connection is successful.

Now we need to open a .env file where we keep our environment variable, you must have a .env file in your project because not all code or variables can be hardcoded for security reseasons.
PORT = 4000
BLOG_CONNECTION_URL=
JWT_SECRET = <your-32-word-secret>
EXPIRATION_TIME = "1h"
BLOG_TEST_CONNECTION_URL = <data connection url for testing>
TEST_TOKEN =<jwt token for testing>
EMAIL_USER = <your email>
EMAIL_PASSWORD =<password for email app>
The next thing to do is to create a .gitignore file, this file help to keep untracked files, especially when we want to push to GitHub, so for now we keep our node_modules and .env file inside so that they won't be pushed together GitHub.
Models
Now that our server is running successfully, the next thing we want to do is to create a model folder and inside this model folder we have two files;
userModel.js
blogModel.js
Inside our userModel.js file, we require mongoose, bcrypt. Mongoose can be used for creating schemas and validating user input, you can check more mongoose and bcrypt in the description of the resource above but the major function of bcrypt is that it performs a hash on user input, especially the password and confirm password.
const bcrypt = require("bcrypt");
const crypto = require("crypto");
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const validator = require("validator");
const ObjectId = Schema.ObjectId;
const userSchema = new Schema({
// id: ObjectId,
email: {
type: String,
lowercase: true,
require: [true, " A user must have a email"],
trim: true,
unique: true,
},
first_name: {
type: String,
minLength: 2,
require: true,
},
last_name: {
type: String,
minLength: 2,
require: true,
},
password: {
type: String,
minLength: 2,
require: true,
trim: true,
require: [true, "please input your password"],
},
confirmPassword: {
type: String,
minLength: 2,
require: true,
validate: {
validator: function (el) {
return el === this.password;
},
message: "password are not same",
},
trim: true,
require: [true, "please input the correct password"],
},
passwordModifiedAt: { type: Date },
active: { type: Boolean, default: true, select: false },
paswordRestToken: { type: String },
passwordResetTokenExpiryTime: Date,
createdAt: {
type: Date,
default: Date.now(),
},
});
userSchema.pre("save", async function (next) {
// Only run this function if password was actually modified
if (!this.isModified("password")) return next();
this.password = await bcrypt.hash(this.password, 12);
// Delete passwordConfirm field
this.confirmPassword = undefined;
next();
});
// pre hook to update the passwordModifiedAt field
userSchema.pre("save", async function (next) {
if (!this.isModified("password") || this.isNew) return next();
this.passwordModifiedAt = Date.now() - 1500;
next();
});
userSchema.methods.correctPassword = async function (
candidatePassword,
userPassword
) {
return await bcrypt.compare(candidatePassword, userPassword);
};
// checks if the password has been modified
userSchema.methods.passwordModified = function (jwt_iat) {
if (!this.passwordModified) return false;
const jwt_iat_ts = new Date(jwt_iat * 1000).toISOString();
return new Date(jwt_iat_ts) < new Date(this.passwordModifiedAt);
};
/// genrating reset password token
userSchema.methods.genResetToken = function () {
const token = crypto.randomBytes(32).toString("hex");
const hashedToken = crypto.createHash("sha256").update(token).digest("hex");
this.paswordRestToken = hashedToken;
this.passwordResetTokenExpiryTime = Date.now() + 10 * 60 * 1000;
return token;
};
const user = mongoose.model("user", userSchema);
module.exports = user;
For our blogModel.js file, we also require mongoose for our blog schema and our blog validation before saving it to the database.
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const ObjectId = mongoose.Schema.ObjectId;
const blogSchema = new Schema({
title: {
type: String,
required: true,
},
description: {
type: String,
trim: true,
},
author: {
type: ObjectId,
ref: "user",
},
state: {
type: String,
enum: ["published", "draft"],
default: "draft",
},
read_count: {
type: Number,
default: 0,
},
reading_time: { type: String },
tags: [String],
body: {
type: String,
trim: true,
required: [true, "you blog must have a body"],
},
timestamp: {
type: Date,
default: Date.now(),
},
});
const Blog = mongoose.model("Blog", blogSchema);
module.exports = Blog;
Controllers
we will be creating three files in the controller folder which are ;
blogControllers
userControllers
authControllers
In our blogController we perform the CRUD function here, we have the postBlog,getAllBlogs, getBlogById, updateBlog, and deleteBlog functions which we export to our blogRoute.js file
const blog = require("../Model/blogModel");
exports.postBlog = async function (req, res, next) {
try {
const blogBody = req.body;
const blogReadingTime = function () {
const blogLenght =
blogBody.body.split(" ").length +
blogBody.title.split(" ").length +
blogBody.description.split(" ").length;
console.log(blogLenght);
const totalReadingtime = blogLenght / 200;
return `${totalReadingtime} minute`;
};
blogBody.reading_time = blogReadingTime();
const newBlog = await blog.create({ ...req.body, author: req.user._id });
return res.status(201).json({
status: "success",
newBlog,
});
} catch (error) {
next(error);
}
};
exports.getAllBlogs = async function (req, res, next) {
try {
const filterBlog = { state: "published" };
const queryObj = { ...req.query };
let blogQuery = blog.find(filterBlog);
//sorting read_count, reading_time and timestamp
if (req.query.sort) {
const searchBy = req.query.sort.split(",").join(" ");
blogQuery = blogQuery.sort(searchBy);
} else {
blogQuery.sort({ timestamp: -1 });
}
//pagination
const page = +req.query.page || 1;
const limit = +req.query.limit || 20;
const skip = (page - 1) * limit;
blogQuery.skip(skip).limit(limit);
const Blogs = await blogQuery;
res.status(200).json({ status: "success", blogList: Blogs.length, Blogs });
} catch (error) {
next(error);
}
};
exports.ownerBlog = async function (req, res, next) {
try {
const filterBlog = { state: "published" };
const queryObj = { ...req.query };
let blogQuery = blog.find(filterBlog);
const Blog = await blog.find({ author: req.user._id });
if (!Blog) {
return new Error("you don,t have access to this blog");
}
const page = +req.query.page || 1;
const limit = +req.query.limit || 20;
const skip = (page - 1) * limit;
blogQuery.skip(skip).limit(limit);
return res
.status(200)
.json({ status: "success", result: Blog.length, Blog });
} catch (error) {
next(error);
}
};
exports.getBlogById = async function (req, res, next) {
try {
const { blogId } = req.params;
console.log("block");
let Blog = await blog.findById(blogId).populate("author");
console.log(Blog);
if (!Blog) {
res.status(404);
const error = new Error("No blog found with that ID");
return next(error);
}
Blog.read_count += 1;
await Blog.save({ validateBeforeSave: true });
res.status(200).json({ status: "success", blogList: Blog.length, Blog });
} catch (error) {
next(error);
}
};
exports.updateBlog = async function (req, res, next) {
try {
const { blogId } = req.params;
const state = req.body;
console.log("book");
const parsedBlog = await blog.findById(blogId);
console.log(parsedBlog);
if (!parsedBlog) {
return next(new Error("this is not your blog"));
}
console.log(parsedBlog.author, req.user._id);
if (parsedBlog.author.toString() !== req.user._id) {
return next(new Error("you are not authorized to upadate blog "));
}
const newBlog = await blog.findByIdAndUpdate(blogId, state, {
new: true,
runValidators: true,
});
return res.status(200).json({ status: "success", newBlog });
} catch (error) {
next(error);
}
};
exports.deleteblog = async function (req, res, next) {
try {
const { blogId } = req.params;
const blogToBeDeleted = await blog.findById(blogId);
if (!blogToBeDeleted) {
return next(new Error("this is not your blog"));
}
if (blogToBeDeleted.author.toString() !== req.user._id) {
return next(new Error("you are not authorized to delete blog "));
}
const Blog = await blog.findByIdAndDelete(blogId);
console.log(Blog);
if (!Blog) {
res.status(404);
const error = new Error("No blog found with that ID");
return next(error);
}
return res.status(204).json({ messsge: "deletion succesful" });
} catch (error) {
next(error);
}
};
Also in userController we did the CRUD function but in this case, it was to getAllUser,getUserById,updateUser,deleteUser and all these functions were exported to our userRoute.js file.
const User = require("../Model/userModel");
exports.getAllUsers = async function (req, res, next) {
try {
const Users = await User.find();
return res
.status(200)
.json({ message: "success", result: Users.length, Users });
} catch (error) {
next(error);
}
};
exports.getUserById = async function (req, res, next) {
try {
const { userId } = req.params;
console.log(userId);
const user = await User.findById(userId);
if (!user) {
return res.status(404).json({ status: false, order: null });
}
return res.json({ status: true, user });
} catch (error) {
return res.status(404).json({ message: "can't get user by id", error });
}
};
exports.updateUser = async function (req, res, next) {
try {
const { userId } = req.params;
const userDetails = req.body;
const user = await User.findById(userId, {
new: true,
runValidators: true,
});
// console.log(user);
if (!user) {
return res.status(404).json({ status: false, order: null });
}
console.log(user);
await User.findByIdAndUpdate(user, userDetails, {
runValidators: true, // Runs validations for the updated fields
});
return res.json({ status: true });
} catch (error) {
res.status(404).json({ message: "user update unsuccessful", error });
}
};
exports.deleteUser = async function (req, res, next) {
try {
console.log(req.params);
const { userId } = req.params;
const user = await User.deleteOne({ _id: userId });
return res.json({ status: true, user });
} catch (error) {
res.status(401).json({ message: "user deletion failed", error });
}
};
The last file in this folder is the authController, this is where we perform our authentication which is the signup,signin, forgetPassword and resetPassword functions, in this file we require quite some modules like jsonwebtoken, crypto,userModel and emailSender from the utils file.
const jwt = require("jsonwebtoken");
const user = require("../Model/userModel");
const crypto = require("crypto");
const userModel = require("../Model/userModel");
const emailSender = require("../Utils/emailSender");
require("dotenv").config();
const secret = process.env.JWT_SECRET;
const signToken = (user) => {
//this function will be called any time i need to sign users data or details
return jwt.sign({ user }, secret, {
expiresIn: process.env.EXPIRATION_TIME,
});
};
// SIGNUP CONTROLLER ROUTE
exports.signup = async function (req, res, next) {
try {
const { email, first_name, last_name, password, confirmPassword } =
req.body;
if (password !== confirmPassword) {
const error = new Error("password does not match");
return next(error);
}
const user = await userModel.create({
email,
first_name,
last_name,
password,
confirmPassword,
});
user.password = undefined;
user.confirmPassword = undefined;
const token = signToken(user);
return res.json({
message: "Signup successfull",
user,
token,
});
} catch (error) {
next(error);
}
};
// SIGIN CONTROLLER ROUTE
exports.signin = async function (req, res, next) {
try {
const { email, password } = req.body;
if (!email || !password) {
const error = new Error("Username or password is incorrect");
return next(error);
}
// check if user exist && password is correct
const user = await userModel.findOne({ email });
if (!user || !(await user.correctPassword(password, user.password))) {
const error = new Error("Incorrect email or password");
return next(error);
}
// if all conditions are passed then send token
user.password = undefined;
const token = signToken(user);
res.status(200).json({
status: "success",
token,
});
} catch (error) {
return next(error, { message: "user login unsuccessful" });
}
};
exports.forgetPassword = async (req, res, next) => {
const { email } = req.body;
const User = await user.findOne({ email });
if (!User) return next(new Error("user can not be found"));
try {
const resetToken = User.genResetToken();
console.log(resetToken);
await User.save({ validateBeforeSave: false });
const resetPasswordURL = `${req.protocol}://${req.get(
"host"
)}/resetPassword/${resetToken}`;
const body = `Forgot your password? Submit a PATCH request with your new password and confirmPassword to: <a href=${resetPasswordURL}>${resetPasswordURL}</a>.\nIf you didn't forget your password, please ignore this email!`;
const subject = "Your password reset token (valid for 10 min)";
await emailSender({ email, body, subject });
return res.status(200).json({
status: "success",
message: "A link to reset your password hs been sent to your email",
});
} catch (error) {
User.paswordRestToken = undefined;
User.passwordResetTokenExpiryTime = undefined;
await User.save({ validateBeforeSave: false });
console.log(error);
return next(
new Error(
"Something went wrong while sending a passoword resent link to email. Please try again later"
)
);
}
};
exports.resetPassword = async (req, res, next) => {
try {
const token = req.params.token;
console.log(token, "book");
const hashedToken = crypto.createHash("sha256").update(token).digest("hex");
console.log(hashedToken);
// /lloking for th user with the reset token
const User = await user.findOne({
paswordRestToken: hashedToken,
passwordResetTokenExpiryTime: { $gt: Date.now() },
});
console.log(User);
if (!User) {
return next(
new Error("password reset token is invalid please try again")
);
}
const { password, confirmPassword } = req.body; // Reset the password
User.password = password;
User.confirmPassword = confirmPassword;
// password reset token will be cleared after a succeful password update
User.paswordRestToken = undefined;
User.passwordResetTokenExpiryTime = undefined;
await User.save({ validateModifiedOnly: true });
User.password = undefined;
User.passwordModifiedAt = undefined;
const jwttoken = signToken(User);
return res.status(200).json({ token: jwttoken, data: { User } });
} catch (error) {
return next(error);
}
};
Routes
In continuation of this project, we'll create our route and inside the route folder we will have three files ;
blogRouter.js
userRouter.js
authRouter.js
In our blogRouter.js we require express, passport, blogValidation blogController and we also did one important thing, which is saving our express router which can be found in line 6 of the code below. And we also used passport as middleware to authenticate all the routes except the getAllBlogs route
const express = require("express");
const passport = require("passport");
const blogValidation = require("../validators/blogValidators");
const blogController = require("../controller/blogController");
const blogRouter = express.Router();
blogRouter.get("/", blogController.getAllBlogs);
blogRouter.get(
"/owner",
passport.authenticate("jwt", { session: false }),
blogController.ownerBlog
);
blogRouter.get("/:blogId", blogController.getBlogById);
blogRouter.post(
"/",
blogValidation,
passport.authenticate("jwt", { session: false }),
blogController.postBlog
);
blogRouter.patch(
"/:blogId",
passport.authenticate("jwt", { session: false }),
blogController.updateBlog
);
blogRouter.delete(
"/:blogId",
passport.authenticate("jwt", { session: false }),
blogController.deleteblog
);
module.exports = blogRouter;
in the user route, we also have almost the same feature as the blog route, we also required passport for route authentication, express, and userController. in our route file we used some HTTP methods like GET, POST, PATCH, and DELETE you can check more HTTP methods.
const passport = require("passport");
const express = require("express");
const userController = require("../controller/userController");
const userRouter = express.Router();
userRouter.get(
"/:userId",
passport.authenticate("jwt", { session: false }),
userController.getUserById
);
userRouter.get("/", userController.getAllUsers);
userRouter.patch(
"/:userId",
passport.authenticate("jwt", { session: false }),
userController.updateUser
);
userRouter.delete(
"/:userId",
passport.authenticate("jwt", { session: false }),
userController.deleteUser
);
module.exports = userRouter;
In the auth route we required express, uservalidation to validate user input, authController.The auth router is majorly meant for authentication.
const express = require("express");
const userValidation = require("../validators/userValidation");
const authController = require("../controller/authController");
const auth_router = express.Router();
// SIGNUP ROUTE
auth_router.post("/signup", userValidation, authController.signup);
// SIGNIN ROUTE
auth_router.post("/signin", userValidation, authController.signin);
auth_router.post("/forgotPassword", authController.forgetPassword);
auth_router.patch("/resetPassword/:token", authController.resetPassword);
module.exports = auth_router;
Validation
For validation of user input, we will be using the joi third-party library, though we can also make use of mongoose as we spoke of earlier to validate user input, joi makes it easier because it has a more customized response when input is successful and when there's an error.
In the validation folder, we have two files for validating user input ;
blogValidator
userValidator
The blogValidator has the following code;
const joi = require("joi");
// const joiObjectId = require("joi-objectid")(joi);
const blogValidationMiddleware = async (req, res, next) => {
try {
await blogSchema.validateAsync(req.body);
next();
} catch (error) {
console.log("HERE", error);
return res.status(406).send(error.details[0].message);
// return res.status(406).send(error.details[0].message);
}
};
const blogSchema = joi.object({
title: joi.string().min(3).max(20).required(),
description: joi.string().min(10).max(200).optional().trim(),
author: joi.ref("user"),
state: joi.array().has(["published,draft"]).default("draft"),
read_count: joi.number().default(0),
reading_time: joi.string(),
tags: joi.string(),
body: joi.string().trim().required(),
timestamp: joi.date().default(Date.now),
});
module.exports = blogValidationMiddleware;
The userValidator file has the following code snippet below
const joi = require("joi");
joiObjectId = require("joi-objectid")(joi);
const userValidatorMiddleWear = async (req, res, next) => {
try {
userValidator.validateAsync(req.user);
next();
} catch (error) {
res.status(406).send(error.details[0].message);
}
};
const userValidator = joi.object({
email: joi
.string()
.email({ minDomainSegments: 2, tlds: { allow: ["com", "net"] } })
.required(),
first_name: joi.string().min(2).required(),
last_name: joi.string().min(2).required(),
password: joi.string().min(2).trim().required(),
confirmPassword: joi.ref("password"),
});
module.exports = userValidatorMiddleWear;
Testing
Testing our endpoints we will be making use of jest and supertest library, testing is the last thing done after building our API, the purpose of testing is to know if the endpoints are working. In our test folder, we have two test files written as ;
blog.test.js
user.test.js
our blog.test.js file should look like the code snippet below
const mongoose = require("mongoose");
const supertest = require("supertest");
jest.setTimeout(30000);
require("dotenv").config();
const BLOG_TEST_CONNECTION_URL = process.env.BLOG_TEST_CONNECTION_URL;
const app = require("../app");
const TEST_TOKEN = process.env.TEST_TOKEN;
let Blog;
beforeAll((done) => {
mongoose.connect(BLOG_TEST_CONNECTION_URL);
mongoose.connection.on("connected", async () => {
console.log("connected to Mongodb successfully");
});
mongoose.connection.on("error", (err) => {
console.log(err);
console.log("An error occured");
});
done();
});
afterAll((done) => {
// mongoose.connection.db.dropDatabase(() => {
mongoose.connection.close(() => done());
// });
});
//BLOG ROUTE TESTING
describe("/blogs", () => {
let blogId;
it("POST/blogs", async () => {
const body = {
title: "blog 5",
body: "i am realy, my name is olawole jethro",
description: "am new jhf sdsdd jdjs jfjf here",
tags: "campaign",
author: "jetpack",
};
const response = await supertest(app)
.post("/blogs")
.set("Authorization", `Bearer ${TEST_TOKEN}`)
.send(body);
blogId = response.body.newBlog._id;
expect(response.status).toBe(201);
expect(response.body.newBlog.title).toBe("blog 5");
expect(response.body.status).toBe("success");
expect(response.body.newBlog.state).toBe("draft");
});
it("GET/blogs?id", async () => {
const response = await supertest(app)
.get(`/blogs/${blogId}`)
.set("Authorization", `Bearer ${TEST_TOKEN}`);
expect(response.status).toBe(200);
expect(response.body.Blog).toHaveProperty("author");
});
it("UPDATE/blogs", async () => {
const blogData = {
state: "published",
};
const response = await supertest(app)
.patch(`/blogs/${blogId}`)
.set("Authorization", `Bearer ${TEST_TOKEN}`)
.send(blogData);
expect(response.status).toBe(200);
expect(response.body.status).toBe("success");
});
it("DELETE/blogs/blogId", async () => {
const response = await supertest(app)
.delete(`/blogs/${blogId}`)
.set("Authorization", `Bearer ${TEST_TOKEN}`);
// console.log(response.body);
expect(response.status).toBe(204);
});
});
our user.test.js file should look like the code snippet below
const mongoose = require("mongoose");
const supertest = require("supertest");
require("dotenv").config();
const TEST_TOKEN = process.env.TEST_TOKEN;
const BLOG_TEST_CONNECTION_URL = process.env.BLOG_TEST_CONNECTION_URL;
const app = require("../app");
jest.setTimeout(30000);
beforeAll((done) => {
mongoose.connect(BLOG_TEST_CONNECTION_URL);
mongoose.connection.on("connected", async () => {
console.log("connected to Mongodb successfully");
});
mongoose.connection.on("error", (err) => {
console.log(err);
console.log("An error occured");
});
done();
});
afterAll((done) => {
// mongoose.connection.db.dropDatabase(() => {
mongoose.connection.close(() => done());
// });
});
describe("sign up", () => {
let userId;
it("POST /", async () => {
const userDetails = {
first_name: "olawole",
last_name: "jethro",
email: "jetpac@gmail.com",
password: "olawes",
};
const response = await supertest(app)
.post("/signup")
.set("content-type", "application/json")
.send(userDetails);
userId = response.body.user._id;
console.log(userId);
expect(response.status).toBe(200);
expect(response.body.message).toBe("Signup successfull");
expect(response.body).toHaveProperty("user");
});
it("GET users/", async () => {
const response = await supertest(app)
.get("/users")
.set("Authorization", `Bearer ${TEST_TOKEN}`);
expect(response.status).toBe(200);
expect(response.body.message).toBe("success");
expect(response.body.result).toBeGreaterThanOrEqual(0);
});
it("GET by ID user/", async () => {
const response = await supertest(app)
.get(`/users/${userId}`)
.set("Authorization", `Bearer ${TEST_TOKEN}`);
expect(response.status).toBe(200);
expect(response.body.status).toBe(JSON.parse("true"));
expect(response.body).toHaveProperty("user");
});
it("UPDATE user by ID /", async () => {
const user_data = {
email: "demo@gmail.come",
};
const response = await supertest(app)
.patch(`/users/${userId}`)
.set("Authorization", `Bearer ${TEST_TOKEN}`)
.send(user_data);
expect(response.status).toBe(200);
expect(response.body.status).toBe(JSON.parse("true"));
});
it("DELETE user by ID /", async () => {
const response = await supertest(app)
.delete(`/users/${userId}`)
.set("Authorization", `Bearer ${TEST_TOKEN}`);
expect(response.status).toBe(200);
expect(response.body.status).toBe(JSON.parse("true"));
expect(response.body).toHaveProperty("user");
});
});

Pushing to GitHub
I will like to show you a few steps on how your can push your newly built project to your GitHub repository.
Create a GitHub account
create a new repository
Then come to your command line terminal to run the code below
git init
git add README.md
git commit -m "first commit"
git branch -M main
git remote add <Your copied repo link>
git push -u origin main/master
Wrapping up
It's a nice thing seeing you at the end of this article and I will like to know if you've gotten one or two things to point out or probably there's anything we can add to improve this article in the comment section below


