Steps to create a project
Step 1: First, we will initiate the Node project using below command. Go to project folder and run below command.
npm init -y
Step 2: Install the required dependencies as mentioned below using below npm command.
npm i express body-parser connect-mongo express-session jsonwebtoken mongoose
nodemon passport passport-jwt passport-local
Project Structure:
The updated dependencies in package.json file will look like:
"dependencies":{
"body-parser": "^1.20.2",
"connect-mongo": "^5.1.0",
"express": "^4.18.2",
"express-session": "^1.17.3",
"jsonwebtoken": "^9.0.2",
"mongoose": "^8.0.3",
"nodemon": "^3.0.2",
"passport": "^0.7.0",
"passport-jwt": "^4.0.1",
"passport-local": "^1.0.0"
}
Example: Add the following codes in respective files.
Javascript
//index.js const express = require( 'express' ); const bodyParser = require( 'body-parser' ); var session = require( 'express-session' ); const MongoStore = require("connect-mongo"); const port = 5000; const app = express(); var { db } = require( './db' ); var authRouter = require( './auth' ); var libraryRouter = require( './library' ); //body-parser configuration app.use(bodyParser.json()) app.use(bodyParser.urlencoded({ extended: true })) //session configuration app.use(session({ secret: 'gfgsecret' , resave: false , saveUninitialized: true , store: MongoStore.create({ client: db.getClient(), dbName: 'testdb' , collectionName: "sessions", stringify: false , autoRemove: "interval", autoRemoveInterval: 1 }) })); app.use( '/' , authRouter); app.use( '/' , libraryRouter); //server listening app.listen(port, () => { console.log(`server started on ${port}`); }); |
Javascript
//db.js const mongoose = require( 'mongoose' ); //database connection mongoose.connect("<YOUR MONGODB CONNECTION URL>"); const db = mongoose.connection; db.on( 'error' , console.error.bind(console, 'connection error:' )); db.once( 'open' , function () { console.log("Connection Successful!"); }); //model and schema creation var UserSchema = mongoose.Schema({ name: String, username: { type: String, unique: true }, password: String, email: { type: String, unique: true }, mobile: { type: Number, unique: true }, admin: { type: Boolean, default : false } }); var BookSchema = mongoose.Schema({ name: String, author: String, genre: String, type: String, available: { type: Boolean, default : true } }, { timestamps: true }) var BorrowerRecordSchema = mongoose.Schema({ username: String, bookid: { type: mongoose.ObjectId, unique: true , ref: 'Book' }, duedate: { type: Date, default : () => new Date(+ new Date() + 15 * 24 * 60 * 60 * 1000), required: 'Must Have DueDate' } }, { timestamps: true }) var ReturnRecordSchema = mongoose.Schema({ username: String, bookid: { type: mongoose.ObjectId, unique: true , ref: 'Book' }, duedate: { type: Date, ref: 'BorrowerRecord' }, fine: Number }, { timestamps: true }) var User = mongoose.model( 'User' , UserSchema, 'user' ); var Book = mongoose.model( 'Book' , BookSchema, 'books' ); var BorrowerRecord = mongoose.model( 'BorrowerRecord' , BorrowerRecordSchema, 'borrowers' ); var ReturnRecord = mongoose.model( 'ReturnRecord' , ReturnRecordSchema, 'returnrecords' ); module.exports = { db, User, Book, BorrowerRecord, ReturnRecord }; |
Javascript
//auth.js const jwt = require( 'jsonwebtoken' ); const JWTStrategy = require("passport-jwt").Strategy; var LocalStrategy = require( 'passport-local' ); var passport = require( 'passport' ); const express = require( 'express' ); var router = express.Router(); var { User } = require( './db' ); //passport local strategy configuration passport.use( new LocalStrategy(async function verify(username, password, cb) { const query = User.where({ username: username }); await query.findOne().then( function (user) { if (user.password === password) { cb( null , user, { status: 200, message: 'Login Successful.' }); } else { cb( null , false , { status: 401, message: 'Incorrect username or password.' }) } }). catch ( function (err) { cb( null , false , { status: 401, message: 'User Does Not Exist' }) }); })); //passport jwt strategy configuration passport.use( new JWTStrategy( { jwtFromRequest: (req) => req.headers[ 'x-access-token' ], secretOrKey: 'examplesecret' , }, (payload, done) => { return done( null , payload); } )); passport.serializeUser( function (user, cb) { process.nextTick( function () { cb( null , { id: user.id, username: user.username }); }); }); passport.deserializeUser( function (user, cb) { process.nextTick( function () { return cb( null , user); }); }); //route for registering user and admin router.post( '/register' , async (req, res) => { //new user creation from request body data var user1 = new User(req.body); await user1.save().then( function (user) { if (user) { console.log(user.name + " saved to user collection."); res.send({ status: 200, message: user.name }); } }, function (err) { //errors for various primary key if (Object.keys(err.keyPattern)[0] == 'mobile' ) { res.send({ status: 500, message: "User with mobile already exist"}); } else if (Object.keys(err.keyPattern)[0] == 'username' ) { res.send({status: 500, message:"User with username already exist"}); } else if (Object.keys(err.keyPattern)[0] == 'email' ) { res.send({ status: 500, message: "User with email already exist" }); } else { res.send({ status: 500, message: "Internal Server Error" }); } }); }); //route for logging user in router.post( '/login' , (req, res) => { passport.authenticate( 'local' , { session: false }, (err, user, info) => { if (err || !user) { return res.send({ status: 401, message: info.message }); } req.login(user, { session: false }, (err) => { if (err) { res.send(err); } var userobject = { username: user.username, mobile: user.mobile, admin: user.admin } var token = jwt.sign(userobject, 'examplesecret' ); req.session.jwt = token; return res.send({ status: 200, token: token }); }); })(req, res); }); //route for logging out user router.post( '/logout' , (req, res, next) => { req.session.destroy( function (err) { if (err) { return next(err); } res.redirect( '/' ); }); }) //route for getting session in frontend router.get( '/session' , (req, res) => { passport.authenticate( 'jwt' , { session: false }, (err, user) => { if (err || !user) { res.send( false ); } else { res.send(user); } })(req, res); }); module.exports = router; |
Javascript
//library.js const express = require("express"); var passport = require("passport"); var router = express.Router(); var { User, Book, BorrowerRecord, ReturnRecord } = require("./db"); //home endpoint router.get("/", (req, res) => { res.send("Welcome To Library Management System"); }); //route for getting all books from database router.get("/getbooks", async (req, res) => { const books = await Book.find({}); res.send({ status: 200, books: books }); }); //route for getting all users from database router.get("/getusers", async (req, res) => { const users = await User.find({}); res.send({ status: 200, users: users }); }); //route for creating a new book router.post("/createbook", async (req, res) => { //new book from request body var book = new Book(req.body); //authentication passport.authenticate("jwt", { session: false }, async (err, user) => { if (err || !user) { res.send({ status: 401, message: "Not Authorized" }); } else { //checking if the user is admin if (user.admin) { //saving book to db await book.save().then( function (saveres) { if (saveres) { res.send({ status: 200, message: saveres }); } }, function (err) { res.send({ status: 500, message: "Internal Server Error", }); } ); } else { res.send({ status: 401, message: "You are not authorized to perform this action", }); } } })(req, res); }); //route for borrowing a new book router.post("/borrowbook", async (req, res) => { //userid and bookid from request var bookid = req.body.bookid; var borrowerusername = req.body.username; //authentication passport.authenticate("jwt", { session: false }, async (err, user) => { if (err || !user) { res.send({ status: 401, message: "Not Authorized" }); } else { if (user.admin) { User.findOne({ username: borrowerusername }) .then((user) => { console.log(user); if (user) { Book.findOne({ _id: bookid }) .then((book) => { console.log("book"); if (book) { if (book.available) { //creating and saving new borrower record in database. var newBorrowerRecord = new BorrowerRecord({ username: user.username, bookid: book["_id"], }); newBorrowerRecord .save() .then((saveres) => { if (saveres) { Book.where({ _id: book["_id"], }) .updateOne({ available: false , }) .then((updtres) => { res.send({ status: 200, message: "book borrowed successfully by " + user.username, }); }); } else { res.send({ status: 500, message: "Error Borrowing Book", }); } }) . catch ((err) => { res.send({ status: 500, message: "Error Borrowing Book", }); }); } else { res.send({ status: 500, message: "Book Is not available", }); } } else { res.send({ status: 500, message: "Book with Id Does Not Exist", }); } }) . catch ((err) => { res.send({ status: 500, message: "Internal Server Error", }); }); } else { res.send({ status: 500, message: "Borrower Does Not Exist", }); } }) . catch ((err) => { res.send({ status: 500, message: "Internal Server Error", }); }); } else { res.send({ status: 401, message: "You are not authorized to perform this action", }); } } })(req, res); }); //route for returning a book router.post("/returnbook", async (req, res, next) => { var bookid = req.body.bookid; var borrowerusername = req.body.username; //authentication passport.authenticate("jwt", { session: false }, async (err, user) => { if (err || !user) { res.send({ status: 401, message: "Not Authorized" }); } else { if (user.admin) { //checking for existance of borrower record in db BorrowerRecord.findOne({ bookid: bookid, username: borrowerusername, }) .then((borrowrec) => { if (borrowrec) { var todaysdate = new Date().toISOString(); //calculation of fine if delayed in returning const fine = 0; if (todaysdate > borrowrec.submitdate) { const diffTime = Math.abs( todaysdate - borrowrec.submitdate ); const diffDays = Math.ceil( diffTime / (1000 * 60 * 60 * 24) ); fine = diffDays * 2; } //creating and saving new return record. var returnrec = new ReturnRecord({ username: borrowerusername, bookid: bookid, duedate: borrowrec.submitdate, fine: fine, }); returnrec .save() .then((saveres) => { if (saveres) { Book.findOne({ _id: bookid }) .updateOne({ available: true }) .then((updtres) => { if (updtres) { res.send({ status: 200, message: "Book Returned Successfully", }); } else { res.send({ status: 500, message: "Error Creating Return Record", }); } }); } else { res.send({ status: 500, message: "Error Creating Return Record", }); } }) . catch ((err) => { res.send({ status: 500, message: "Internal Server Error", }); }); } else { res.send({ status: 500, message: "No Record Found", }); } }) . catch ((err) => { res.send({ status: 500, message: "Internal Server Error", }); }); } else { res.send({ status: 401, message: "You are not authorized to perform this action", }); } } })(req, res); }); //route for paying fine router.post("/payfine", (req, res) => { //return record id from request. var returnrecid = req.body.returnrecordid; //authentication passport.authenticate("jwt", { session: false }, async (err, user) => { if (err || !user) { res.send({ status: 401, message: "Not Authorized" }); } else { if (user.admin) { //paying fine by updating return record in database. ReturnRecord.findOne({ _id: returnrecid }) .updateOne({ fine: 0 }) .then((updtres) => { if (updtres) { res.send({ status: 200, message: "Fine Paid Successfully", }); } else { res.send({ status: 500, message: "Error paying Fine", }); } }) . catch ((err) => { res.send({ status: 500, message: "Internal Server Error", }); }); } else { res.send({ status: 401, message: "You are not authorized to perform this action", }); } } })(req, res); }); module.exports = router; |
Steps to run the application : Run the following command in the terminal.
nodemon index.js
NOTE : For accessing routes which requires LOGIN you need to pass JWT token as ‘x-access-token’ from headers as below .
List of All API links :
- http://localhost:5000/
- http://localhost:5000/register
- http://localhost:5000/login
- http://localhost:5000/logout
- http://localhost:5000/session
- http://localhost:5000/getbooks
- http://localhost:5000/getusers
- http://localhost:5000/createbook
- http://localhost:5000/borrowbook
- http://localhost:5000/returnbook
- http://localhost:5000/payfine
Output:
Library Management Application Backend
Library Management System backend using Express and MongoDB contains various endpoints that will help to manage library users and work with library data. The application will provide an endpoint for user management. API will be able to register users, authenticate users, borrow books, return books, create books, pay fine . We’ll be using NodeJS, Express and MongoDB. So, let’s get started with building the backend.
Note: Follow given link to build a Web application on Library Management System.
Preview of final output: Let us have a look at how the final application will look like.
Contact Us