If you haven't read the last post, I recommend you to check it out here, else many things in this post will not make sense.
In the last post we've created a simple index('/') route with HTML file as response using EJS template engine. Now, it's time to look into middlewares and how can we use them to serve our routes with the same prefix easily.So let's get started with the middlewares.
Middleware functions are functions that have access to the request object (req), the response object (res), and the next function in the application’s request-response cycle.The next function is a function in the Express router which, when invoked, executes the middleware succeeding the current middleware.
For example, let's say you have a route ('user/login') in your express app to login the user. Now you want to check the credentials given by users with the credentials stored in the database and authorize that user to the account.And when do you check this credentials? After the user sends request and before your application sends the response. And that's when the middlewares comes in handy. You can write your logic to authenticate the user in the middleware function and response to the user according the return value of the middleware function.Other than authentication, middlewares have many uses as well.
To use the middleware function, we need to add app.use(middlewareFunctionName);
in our code. And that will add the defined middleware function to all the routes that we define in our application. It is called the 'application level middleware'. But we can also add middlewares to particular routes of our choice by providing that route as the first argument in the app.use function. i.e : app.use('/', middlewareFunctionName);
Now, let's add middlewares in our code to serve the routes from routes directory.
app.use('/', require('./routes/index'));
Now let's create the user registration page in our app. But that will require MongoDB database. So, I created an account on MongoDB Atlas, they provide 500MB of free database hosting. And I got the database URL from that which we'll be using to connect to our database. the url seems something like this.
"mongodb+srv://<username>:<password>@cluster0-kmdpn.mongodb.net/test?retryWrites=true&w=majority
First of all, let's use mongoose and the database URL and see if we can connect to our databse.We will need mongoose package and we'll use it's connect
method to connect to our database. Let's add the below code to our app.js
file.
const mongoose = require("mongoose");
const DATABASE_URL = "mongodb+srv://<username>:<password>@cluster0-kmdpn.mongodb.net/test?retryWrites=true&w=majority";
mongoose.connect(DATABASE_URL, (err) => {
if (err) console.log(err);
else console.log("Connected to DB.");
})
Now we can start the server and see if we've connected to the database or not but we are currently working on a localhost server and this code is in our machine only but when we deploy our application online on cloud, we don't want everyone to see the DATABASE_URL as it contains our username and password of the database. So, to protect it we can use .env
file to store our secret credentials.And while uploading it online we won't be adding this .env
file. To use it let's install the 'dotenv' npm package.
$ npm install dotenv
Then,create a .env
file in the project directory and add DATABASE_URL to this file. And to use the value from this file in our application we can make following changes.
require("dotenv").config();
// To connect to MongoDB Database
mongoose.connect(
process.env.DB_CONN,
(err) => {
if (err) console.log(err);
else console.log("Connected to DB!");
}
);
Okay!! So now we have our application connected to our database.
Now,let's create a database model which is basically a schema of our user's information. So first let's create a new directory 'Models' in our app directory and create a new file User.js
. In this file, we'll write the below code to create and export our model.
We'll need 4 field in our User model. Name, Contact Number, State, and Active. In which, Name,Number and State fields will be String type and Active field will be Boolean type.
const mongoose = require("mongoose");
const UserSchema = mongoose.Schema({
name: {
type: String,
required: true,
},
number: {
type: String,
required: true,
},
state: {
type: String,
required: true,
},
active: {
type: Boolean,
required: true,
default: true,
},
});
module.exports = mongoose.model("User", UserSchema);
Now, we have our User model ready with us. Now, we we'll create routes and create HTML page to register a user. Let's start by creating ('/users/register') route. Create a new file users.js
in routes directory and add the below code.
const express = require("express");
const router = express.Router();
router.get('/register', (req,res) => {
res.render('register');
});
module.exports = router;
Here we've used an in-built express middleware Router. Using router instance, we can easily serve routes with same prefix which is 'user'. We'll be creating more routes with this 'user' prefix and therefore we can take advantage of the Router middleware.Now, let's create a form for users to register in the register view that we are rendering to the register route.
<div class="jumbotron">
<form action="/users/add_user" method="post">
<fieldset>
<legend
style="text-align: center; text-decoration: underline;"
class="mt-3"
>
Register Now
</legend>
<div class="form-group">
<label for="name">Name</label>
<input
type="text"
name="name"
class="form-control"
id="name"
required="true"
placeholder="Enter Your Name"
/>
</div>
<div class="form-group">
<label for="phone">Phone Number</label>
<input
name="number"
type="text"
class="form-control"
id="number"
required="true"
aria-describedby="phoneHelp"
placeholder="Enter Your Number"
/>
<small id="phoneHelp" class="form-text text-muted"
>We'll never share your number with anyone else. Promise!</small
>
</div>
<div class="form-group">
<label for="state">State</label>
<select
class="form-control"
id="state"
name="state"
style="cursor: pointer;"
required="true"
>
<option
selected="selected"
id="state_default"
value=""
style="display: none;"
>Select State</option
>
<option value="Gujarat">Gujarat</option>
<option value="Maharashtra">Maharashtra</option>
</select>
</div>
<button type="submit" class="btn btn-primary">Count Me In!</button>
</fieldset>
</form>
</div>
As we've added the path /users/add_user
in the action attribute of the form tag, let's create that route in our users.js
file to register user to our database.
In this, first we'll check if the phone number entered by the user already exist in our database, if it exists we'll redirect the user to the already_registerd
page and if it doesn't exist already, we'll add it our database and redirect the user to the register/successful
page. This is going to be a little bit complex, let's start coding.
const User = require("../models/User"); // To access the User Model
router.post("/add_user", async (req, res) => {
try {
const { name, number, state } = req.body; // Getting Form Fields From The Request Body.
const new_user = await User.aggregate([{ $match: { number: number } }]); // Checking if the number already exists.
if (new_user.length != 0) {
res.render("already_registered",
{
message: "It Seems Like, This number is already registered with us.",
}
);
} else {
// Create a new user object to add to the DB.
const user = new User({
name: name,
number: number,
state: state,
});
const addedUser = await user.save(); // Saving the user to the database.
res.redirect("/users/register/successful");
}
} catch (error) {
console.log(error);
res.json({ message: error });
}
};
And Done!! Really?? No, This code will generate an error and that's because we can't directly use the request body in our app. We'll have to convert it to JSON to be able to use it in our application. And to do that we'll use body-parser
package. Let's add that in app.js
and we are done with the registration!!
$ npm install body-parser;
const bodyParser = require("body-parser");
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
And now we are finally done!! Now in the next post we'll add the most exciting part of this application - the Twilio API and we'll send the users an SMS when they register to let them know they have registered successfully and also we'll create a route to receive the message from the users, if they want to stop our service. Fun things are coming up!!
But for now, That's it. Thank you for reading!