DEV Community

Cover image for Database integration🪢 in node/express - A maintainable approach
Smitter
Smitter

Posted on

Database integration🪢 in node/express - A maintainable approach

Welcome to part 2. Follow along this series to develop a feature-packed 3-tier Authentication System outlined in successive parts.

Summary: In this article, we learn to integrate a node application with a database using a promise-based ODM/ORM in a maintainable approach.

Note 🔔:

A complete Repo of this series can be found on Github✩. Drop a star💫️ if you found it useful.

Table of Contents

  1. Directory Structure
  2. Create package.json
  3. Create .env file
  4. Install dependencies
  5. Set up database connection
  6. Run database connection in application
  7. Conclusion

Directory structure

📂server/
  ├── 📄package.json
  ├── 📄.env
  └── 📂src/
      ├── 📄index.js
      └── 📂dbConn/
           └── 📂mongoose/
               └── index.js
Enter fullscreen mode Exit fullscreen mode

This is the structure with focus on the src directory. The src directory will contain files with code we write to run our application. We will add code in these files as we progress through the article. You can always double check to create these files in their correct locations.

Create package.json

From the root level of server directory, run the command npm init -y.

This command will generate a package.json file inside our server folder. Then edit the package.json file to look like this:

{
    "name": "api",
    "version": "1.0.0",
    "description": "",
    "private": "true",
    "main": "src/index.js",
    "scripts": {
        "start": "node src/index.js",
        "dev": "nodemon src/index.js",
        "test": "echo \"Error: no test specified\" && exit 1"
    },
    "keywords": [],
    "author": "hane-smitter",
    "license": "MIT"
}
Enter fullscreen mode Exit fullscreen mode

Importantly, change the main property to point to "src/index.js" which will be the entry file to our application. And also add "start" and "dev" scripts:

// ...
"scripts": {
    "start": "node src/index.js",
    "dev": "nodemon src/index.js",
    "test": "echo \"Error: no test specified\" && exit 1"
}
// ...
Enter fullscreen mode Exit fullscreen mode

Create .env file

A .env or dotenv file is a key-value text configuration file for defining application's environment constants.

Let's create environment variables our application will use.

To do this, create a .env file at the server directory root(refer) and add the following variable(s):

MONGODB_URI=
Enter fullscreen mode Exit fullscreen mode

MONGODB_URI is the MongoDB database connection string. It is currently empty but we will assign a value to it later on.

Note: Remember to include .env file to your .gitignore, should you initialize a git project. .env file is meant to be private to you and should not be shared outside of your local repository.

Install dependencies

We have initialized our project with package.json file. We can now add dependencies from the npm registry that we will need in this project.

We will use the following dependencies:

  • Express - A web framework written in JavaScript and hosted within the Node.js runtime environment, to generally help us handle requests coming to our server.
  • Mongoose - An object modelling tool for MongoDB to allow us to enforce a specific mongoDB schema from our application.
  • Dotenv - To load environment variables declared in .env file.
  • Nodemon - To restart our server after file changes.

Therefore install the dependencies with terminal opened from the root of server directory by running the command:

npm install mongoose express dotenv --save
Enter fullscreen mode Exit fullscreen mode

Then install nodemon as a development dependency, which means that we only need nodemon during development time of our application:

npm install nodemon --save-dev
Enter fullscreen mode Exit fullscreen mode

Set up database connection

In this step, we will connect to a MongoDB database hosted in the cloud, i.e MongoDB Atlas. If you do not have MongoDB installed locally on your machine, you can still hit the ground running with the hosted version👍.

First, you will need a connection string connecting to MongoDB as a cloud service. Create MongoDB Atlas account or login if you already have one. Then follow this guide to obtain your connection string.

Once you have your connection string, open the .env file and set the MONGODB_URI like shown:

MONGODB_URI=mongodb+srv://<user>:<password>@sample.host/<db_name>?retryWrites=true&w=majority
Enter fullscreen mode Exit fullscreen mode

You can as well substitute with URI of local mongoDB installation. In this case your connection URI will look like: mongodb://127.0.0.1:27017/<dbname>.

Then, open terminal at server directory root, create src directory and change into it:

mkdir src
cd src
Enter fullscreen mode Exit fullscreen mode

src is where code we write for our backend will reside.

We will start by creating a file for our MongoDB connection.

Open/create index.js file located at server/src/dbConn/mongoose/(refer). Paste the following code in it:

const mongoose = require("mongoose");

// Pull in environment variable
const connURI = process.env.MONGODB_URI;

mongoose.set("strictQuery", false);
mongoose.set("bufferCommands", false); // Disable buffering

// Connect to MongoDB and store connection in variable
const db = mongoose.connect(connURI);

db.catch((err) => {
    if (err.message.code === "ETIMEDOUT") {
        console.log(`----${err.message.code}----`);
        // console.log(err);
        mongoose.connect(connURI);
    }
    console.log(`----${err.message}----`);
});

module.exports = db;
Enter fullscreen mode Exit fullscreen mode

The code above is straight-forward where we get connection string to our MongoDB database from the environment variable: const connURI = process.env.MONGODB_URI;. We connect to it and store the conection in db variable. We chain catch() to handle error that may occur during the connection. Though we don't handle the "fulfilled" case here. And if a timeout error occurs, we retry to connect. Otherwise we just log the error to the terminal.

Finally we default export the mongoose connection stored in db variable.

Run database connection in application

Here we need to include database connection in our entry file where it will be actually run on application start-up. And we synchronize the successful database connection to server listening on Tcp port.

Open/create the entry file to our application. This file should be index.js located at server/src/(refer). Remember that this is the file referenced by the "main" property in our package.json file.

Add the following code inside this file:

require("dotenv").config();
const express = require("express");

const dbConnection = require("./dbConn/mongoose");

/* 
   1. INITIALIZE EXPRESS APPLICATION 🏁
 */
const app = express();
const PORT = process.env.PORT || 8000;

/* 
   2. APPLICATION MIDDLEWARES AND CUSTOMIZATIONS 🪛
 */

/* 
   3. APPLICATION ROUTES 🛣️
 */
// Test route
app.get("/", function (req, res) {
    res.send("Hello Welcome to API🙃 !!");
});

/* 
   4. APPLICATION ERROR HANDLING 🚔
 */

/* 
   5. APPLICATION BOOT UP 🖥️
 */
app.on("ready", () => {
    app.listen(PORT, () => {
        console.log(`App running on port ${PORT}`);
    });
});
dbConnection.then(() => {
    console.log("---Database is connected !!---");
    app.emit("ready");
});
Enter fullscreen mode Exit fullscreen mode

Note: The file index.js has commented sections that are numbered. Each section will have its logic added in other parts of the series.

In the snippet above, we have imported dotenv at the very top to load variables from .env file into the environment of the Operating System as early as possible.

On the 5th section, we connect to the database and once successfully connected, we emit app's "ready" event that will inturn launch our application listening on a Tcp PORT.

Therefore our Nodejs Server will start listening for requests after we are certain a successful database connection has been established.

We can test to see our app running on PORT. Open terminal at the server root and run:

npm run dev
Enter fullscreen mode Exit fullscreen mode

If successful, you should see a terminal output like this:


Terminal npm run command



Output of npm run dev command

Open your browser and browse to http://localhost:8000/ to send first request to server. And...🫰, you should see TEST ROUTE has responded:


Test route response



TEST ROUTE response

So we can draw a conclusion that we connected to our database and server then started listening on TCP port. You can mess with the MongoDB connection string to see how err influences what happens next.

Conclusion

Well that is how you can perform database integration in NodeJs application. Mongoose is a promise-based Object Document Mapper(ODM). It let's us connect and run database operation on MongoDB using an object-oriented paradigm. We have approached database integration in a maintainable fashion. You can change to a different database flavour using another promise-based ORM/ODM, while having little to refactor on the entry file. Also the logic that connects to a database is placed in a separate module that contains everything necessary to execute one functionality i.e connecting to a database.

MongoDB has "almost" zero data validation. A database is mostly useful if it has some data validation, at least when we want to work with structured data. Using an ODM like mongoose will help to validate data before we put it in the DB e.g enforcing column types. MySQL is quite a legendary with a legion of in-built data validation. Nonetheless generally ORM/ODM help working with database a bit easier with its abstraction layer. Hence simplifies development.

So this is how we connect to database in this series. Check out the next part where we learn how to win at CORS battleground. Yes, how to fix that irritating CORS error.

You wanna say something? Light up💡 the comment section 🕳🤾.


Thanks for reading. Let's connect @twitter. You may want to be part of the ideas I share.

Top comments (4)

Collapse
 
yaldram profile image
Arsalan Ahmed Yaldram

Ah! this article was helpful. I have always connected to the Database after I start my node server, I see many people do it too. There are many benefits of the above approach no doubt.

Collapse
 
smitterhane profile image
Smitter

I am glad you found it useful

Collapse
 
losinigo profile image
losinigo

Wonderful series! I've had little experience with this whole authentication process and I'm in need to review this again. Thank you!

Collapse
 
smitterhane profile image
Smitter

Welcome, you can always refer to this article again