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 frameworkbcrypt
: To help with encryption and decryption and databody-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 ๐โจ