Handling Form Data -NodeJs and MongoDb

ยท

5 min read

Handling Form Data -NodeJs and MongoDb

Objectives

At the end of this article, you should know how :

  • Servers are being sent.

  • Forms are being handled

  • Responses are being sent

  • A database is being configured

  • The server communicates to the client

The Situation We'll Examine

We will work with this scenario throughout this article.

You are receiving a signup form data and you are to add it to your company's database when users log in you should cross-check if the email matches the password in the database.

NOTE: An email can only be used once.

Solution

Necessary Packages

  • express: To make use of the Express.js framework

  • bcrypt: To help with encryption and decryption and data

  • body-parser: To help with receiving data from the request body

npm install express bcrypt body-parser

Before we carry on, let's set up our database, since we would continuously refer to it, it's advisable to set it up as an exportable function.

//config/dbconfig.js
const MongoClient = require("mongodb").MongoClient;
const url = "YOUR MONGO CLIENT URL GOES HERE";
const dbName = "mydb";
let dbInstance = null;

//function to connect db
async function connectToDatabase() {
  //To ensure that you don't run another database instance when there is one running in the background
  if (dbInstance) {
    return dbInstance;
  }
  //Running a db instance
  try {
    //Connecting to the db
    const client = await MongoClient.connect(url);
    const db = client.db(dbName);
    //Assigning the db to the global variable- dbInstance and returning it
    dbInstance = db;
    return dbInstance;
  } catch (err) {
    //Handling connection error
    throw err;
  }
}

module.exports = connectToDatabase;

Sign Up

Import all necessary packages and run the server on a specific port, here I'll use 8080.

//index.js
const express = require("express");
const bodyparser = require("body-parser");
const app = express();
app.use(bodyparser.urlencoded({ extended: false }));
app.use(bodyparser.json());

app.listen(8080, () => {
  console.log("Server is running");
});

Use POST method to create the signup endpoint and receive the signup information from the client side.

//index.js
const express = require("express");
const bodyparser = require("body-parser");
const app = express();
app.use(bodyparser.urlencoded({ extended: false }));
app.use(bodyparser.json());
app.post("/signup");
app.listen(8080, () => {
  console.log("Server is running");
});

From the instructions in the scenario given, we are to ensure an email can only be used once.

So, we can create a function that checks for the absence of the email

// utilities/signup.utility.js
const connectToDatabase = require("../config/dbconfig");
const existingUser = async (req, res, next) => {
  try {
    //Connect to db
    var db = await connectToDatabase();
    //Get all data in a specific collection- "Users" in this example
    var usersCollection = await db.collection("Users");
    const result = await usersCollection.findOne({
      email: req.body.email
    });
    result
      ? res.status(409).json({ success: false, message: "Existing user" })
      : next();
  } catch (error) {
    res.send(error);
  }
};

In the above function, we connect to our database, access the collection which we are working with then search for the email among all data in the collection, then if found we send an "Existing user" message as a response, if not we move to the next function.

That settled, we can now write a function that adds the user to the database

// utilities/signup.utility.js
const connectToDatabase = require("../config/dbconfig");
const addUser = async (req, res) => {
  let mail = req.body.email;
  //conversion to lowercase to prevent case sensitiveness
  var lowercaseEmail = mail.toLowerCase();
  let info = {
    name: req.body.name,
    email: lowercaseEmail,
    pswd: req.body.pswd
  };

  try {
    var db = await connectToDatabase();
    var usersCollection = await db.collection("Users");
    usersCollection.insertOne(info);
    res.status(200).json({ success: true });
  } catch (error) {
    res.status(503).json({ success: false, message: error });
  }
};

We have successfully written a function that adds the data to our database, now we go back to our index.js file and work on our signup endpoint.

//index.js
const express = require("express");
const bodyparser = require("body-parser");
const {existingUser, addUser} = require("./utilities/signup.utility.js");
const app = express();
app.use(bodyparser.urlencoded({ extended: false }));
app.use(bodyparser.json());
app.post("/signup", existingUser, addUser);
app.listen(8080, () => {
  console.log("Server is running");
});

In the above code, we imported the signup utilities, and in the endpoint, we called the functions in the right order- existingUser then addUser. This way the existing user function runs first and will only proceed to the addUser function if the user does not exist.

NOTE: The functions could only have been imported because they were exported from the signup.utility.js file.

Here's what the full code looks like :

// utilities/signup.utility.js
const connectToDatabase = require("../config/dbconfig");

const existingUser = async (req, res, next) => {
  try {
    //Connect to db
    var db = await connectToDatabase();
    //Get all data in a specific collection- "Users" in this example
    var usersCollection = await db.collection("Users");
    const result = await usersCollection.findOne({
      email: req.body.email
    });
    result
      ? res.status(409).json({ success: false, message: "Existing user" })
      : next();
  } catch (error) {
    res.send(error);
  }
};

const addUser = async (req, res) => {
  let mail = req.body.email;
  var lowercaseEmail = mail.toLowerCase();
  let info = {
    name: req.body.name,
    email: lowercaseEmail,
    pswd: req.body.pswd
  };

  try {
    var db = await connectToDatabase();
    var usersCollection = await db.collection("Users");
    usersCollection.insertOne(info);
    res.status(200).json({ success: true });
  } catch (error) {
    res.status(503).json({ success: false, message: error });
  }
};
module.exports = { existingUser, addUser };

Login

To allow login we just have to ensure the email is present in our database and matches its password if present.

We would also use a POST method based on the fact that we are receiving data from our client-side

//index.js
const express = require("express");
const bodyparser = require("body-parser");
const { existingUser, addUser } = require("./utilities/signup.utility.js");
const connectToDatabase = require("./config/dbconfig.js");
const app = express();
app.use(bodyparser.urlencoded({ extended: false }));
app.use(bodyparser.json());
app.post("/signup", existingUser, addUser);
app.post("/login", async (req, res) => {
  var { email, pswd } = req.body;
  var db = await connectToDatabase();
  var usersCollection = await db.collection("Users");

  const result = await usersCollection.findOne({ email: email.toLowerCase() });
  try {
    result
      ? email === result.email && pswd === result.pswd
        ? res.status(200).json({ success: true, message: "Login Successful" })
        : res.status(401).json({
            success: false,
            message: "Email and Password do not match"
          })
      : res
          .status(404)
          .json({ success: false, message: "Account does not exist" });
  } catch (error) {
    res.status(503).json({ success: false, message: error });
  }
});
app.listen(8080, () => {
  console.log("Server is running");
});

The above function in the login endpoint, checks if the email is present in the database, if yes it then goes add to test if the email provided matches the password that was provided for it in the database. Each response was given based on the condition it fulfilled.

We have completed our task successfully โœ…๐ŸŽ‰๐ŸŽŠ

Conclusion

NOTE: The above article doesn't cover authentication, authorization, encryption, decryption e.t.c

The aim of the article is just to cover the basics of form handling in nodejs with a mongodb database.

Subscribe for more tech-related content ๐ŸŽ‰โœจ

ย