Open In App

Library Management Application Backend

Last Updated : 19 Jan, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

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.

Screenshot-(15)

Prerequisites:

Approach to create Library Management Application Backend:

  • We will build an express server that will act as a backend API.
  • Then we will configure MongoDB Atlas for storing library data.
  • Then we will configure server for managing library data with Mongoose.
  • We will add routes for getting users and books from backend with GET request.
  • For authentication we will add login, logout , session route which use jwt and local passport authentication.
  • Then we will add route create book which will create new book by taking book data from client.
  • Similarly, we will add routes that will perform borrow and returning of book to library.
  • All the above routes will use HTTP POST request.
  • Finally, we will create another POST request for paying fine which can be modified later as per requirement to add more complex payment logic.

Functionalities:

  • Register User: Register and save user as admin or member into collection.
  • Authenticate: Authenticates user with username and password.
  • Get Books : Can View all available books in system.
  • Get Users : Can view all available users in system.
  • Create Book: creates and save new book in collection.
  • Borrow book: Allow user to borrow available book from system.
  • Return Book: Allow user to return borrowed book back to system.
  • Pay fine: Pay fine if charged for book.

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:

Screenshot-(25)k

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 .

Screenshot-(18)

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:

ezgif-1-4f47e8729a



Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads