CodeX
Published in

CodeX

Photo by AltumCode on Unsplash

Creating an MVC application using NODEjs and MariaDB

The Stack

The MVC or model-view-controller is a design pattern that separates an application into three main components: Models, Views, and Controllers. To put it simply, models manage data, views present data, controllers are an interface for the other ones.

This MVC application will be built with the Nodejs run environment. Nodejs uses the google V8 engine that allows the execution of JavaScript code outside of a web browser. The single thread event loop model architecture with non-blocking I/O operations provides a way for the handling of concurrent requests without the need of creating multiple threads. These characteristics make Nodejs a good choice to build efficient applications. Moreover, we will also use the Express framework that provides several features to make it easier and faster to develop web applications with Nodejs.

In terms of the database engine, we will use the MariaDB. MariaDB was built by the original developers of MySQL and guaranteed to stay open source and is currently being used by famous users like Google or Wikipedia. Instead of using an object-relational mapper (ORM) like the popular Sequelize, the queries will be written manually through Nodejs MariaDB connector.

To implement the views, the template engine EJS (embedded JavaScript) is going to be used. EJS has a fast learning curve because the code you need to write is basically HTML markup combined with basic JavaScript code.

Before getting started I think it’s appropriate to set the goals and limitations. The main purpose of this tutorial is to propose a strategy that can be used when you create an MVC application using Nodejs. For that, we will build a simple login page where you can authenticate and see a user profile page. We will implement basic role-based access control to distinguish between an administrator and a normal role. It will not cover many of the aspects that you would need to take into consideration when you develop an application to deploy in a production environment. For example, error handling, logging, or basic security measures(like encrypting passwords) are not covered.

Get Started

To be able to proceed with this tutorial you should have installed:

  • NPM or another package manager like Yum;
  • Nodejs;
  • MariaDB Server.

Well, let’s start by creating the following folder structure:

mkdir controllers models views

Open your terminal and enter npm init -y to create our package.json file without asking any questions. In this tutorial, I am not covering what you need to take into consideration when you are configuring your package file. Let’s install the node modules by entering:

 npm install mariadb express express-session body-parser passport dotenv ejs

The dotenv module enables the loading of environment variables from a .env file into process.env. In this case, we are using dotenv to store database configurations and server port. Create a .env file in the root folder of your application and copy these configurations that will be later loaded by calling dotenv.config().

DB_HOST=localhostDB_DATABASE=myappDB_USER=adminDB_PASSWORD=mypassSERVER_PORT=3000

Change the content to fit your database server configurations. Now create a server.js file in the same folder and start by import express and dotenv. Add the express listen to function to create the HTTP server.

const express = require(“express”); const dotenv = require(“dotenv”);const app = express();dotenv.config();app.listen(process.env.SERVER_PORT, function () {console.log(“Server listening at: “ + process.env.SERVER_PORT)});

Try to start your server with the command node server.js, you should get a terminal message with “Server listening at 3000”. Right now, the root of your application should look like this:

In the ‘views’ folder create a folder named partials and inside create a headers.ejs file. In this file, we will put some HTML code that can be imported by other ejs files. This ejs feature is particularly useful when there is common code in different pages like a navbar, footer, or header. In this case, we are using this more to show the concept than for practical reasons.

In the views folder, we need to create a login.ejs file with our HTML markup combined with the javascript from ejs. This file will import the header.ejs file from the partials folder.

Take a look at the <% if (errors.length) { %> block. With this snippet, we can send an error variable and show to the end-user an error message. The generated HTML will not include anything if the error variable doesn’t contain any message.

In the controllers, folder creates a login.route.js file with our first routing.

const express = require("express");const router = express.Router();router.get("/", function (request, response) {   response.render("login", { errors: [] });});module.exports = router;

Go back to the server.js file and set the EJS as the view engine and tie the login routing file with the Login endpoint.

app.set("view engine", "ejs");app.set("views", "views");app.use("/login", require("./controllers/login.route"));

Start again our app and open your browser at http://localhost:3000/login . You should be able to see the login page.

The next step is to create a database connection pool. Create utils folders in the root of your application and inside create a db.js file with the following content.

Basically, we create a new pool of connections of the MariaDB server and wrap the ability to get new connections in the getConnection function. The details to access the database are fetched from the dot env file.

Now open your SQL IDE and create the USERS table with two users: one user with the admin role and the other a normal user.

CREATE DATABASE myappCREATE TABLE USERS( ID int NOT NULL AUTO_INCREMENT PRIMARY KEY,USERNAME varchar(100),EMAIL varchar(100),ROLE varchar(100),PASS varchar(100));INSERT INTO USERS(USERNAME,EMAIL,ROLE,PASS)VALUES(‘John’,’a@myemail.com’,’USER’,’mypassword’);INSERT INTO USERS(USERNAME,EMAIL,ROLE,PASS)VALUES(‘Mary’,’b@myemail.com’,’ADMIN’,’mypassword’);

In the models, the folder creates a user.model.js file and declares the read, list, and areValidCredentials functions. Read is used to fetch user information, list to get a list of all users, and areValidCredentials to check if the login credentials are right. In each function, we request a new connection from the connection pool, and after the data is fetched we close the connection.

Inside the utils, the folder creates a new file called auth.js. In this file, we will include the authentication part of the application. Start by importing the express-session module that allows server-side session storing with the client receiving a cookie with the session id. We will use the default configuration to store the session information on the server-side (Memory). In the passport serializeuser function, we choose what user information we want to store in the session, in this case, we are storing just the username. The whole user object is later retrieved from the database in the deserielizeduser function and saved to request.user. The checkAuthentication function can be used as a simple role-based authorization middleware where the role can be passed at route level and compared with the role of the user stored in request.user.

In the server, the file adds the bodyParser middleware and initializes the authentication. It is important to add this middleware before the app.use(route,routefile). Otherwise, the passport is not going to be initialized and you will get an error.

const bodyParser = require(“body-parser”)app.use(bodyParser.json(), bodyParser.urlencoded({ extended: true }));const auth = require(“./utils/auth”);auth.initialization(app);

Create a profile.route.js file in the controller's folder. Basically, we will have a profile/user and profile/admin routes where we use the checkAuthentication middleware to restrict the access to the role we pass. Users can access a page with their profile while admins can access their profile and the list of the users.

Add the profile route in the server.js

app.use(“/profile”, require(“./controllers/profile.route”));

Change the login router file to take into consideration the login process. The get method renders the login page or, if the user is authenticated, redirects to the profile page. The post method checks if the credentials are valid and if they are login the user through request.login(user). Instead of this custom approach, we could use the passport local strategy that accomplishes basically the same. We also include here the route that allows for logout. For that we just call request.logOut().

Create a profile.ejs in the views folder. This file renders the user data and if the user is admin it also renders the list of the users in the database.

Start our server again and check if you are able to login with both users. Thanks for reading this tutorial you can check the project code here. Feel free to make suggestions to improve the article quality.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store