DEV Community

Hasan Zohdy
Hasan Zohdy

Posted on

16-Nodejs Course 2023: Application Configurations

So we stopped at the database connection in our last lesson. Now we will create a configuration file for our application.

Why do we need a configuration system?

We need a configuration system to store the configuration of our application. This configuration will be used to connect to the database, to connect to the server, to connect to the logger, etc. We will store all of these configurations in one place so we can easily later change it if we need to.

Create configurations directory

Create config folder inside src folder. Then create database.ts file inside config folder.

Create database configuration file

// src/config/database.ts

export const databaseConfigurations = {
  host: 'localhost',
  port: 27017,
  username: 'root',
  password: 'root',
};
Enter fullscreen mode Exit fullscreen mode

So we created a simple configuration object, that contains the main 4 configurations for the database connection. We will use this configuration object to connect to the database.

Before we go on, let's add an alias to our config folder. Open tsconfig.json file and add the following line to compilerOptions object:

"paths": {
  "@config/*": ["src/config/*"]
}
Enter fullscreen mode Exit fullscreen mode

Now let's update it in our connection class.

// src/database/connection.ts
import { MongoClient } from "mongodb";
import { databaseConfigurations } from 'config/database';

export class Connection {
  /**
   * Mongo Client
   */
  public client?: MongoClient;

  /**
   * Connect to the database
   */
  public async connect() {
    try {
      // 👇🏻 We updated the connection string for the host and port
      this.client = await MongoClient.connect(
        `mongodb://${databaseConfigurations.host}:${databaseConfigurations.port}`,
        {
          auth: {
            // 👇🏻 Replace username and password
            username: databaseConfigurations.username,
            password: databaseConfigurations.password,
          },
        },
      );
      console.log("Connected!");
    } catch (error) {
      console.log(error);
    }
  }
}

const connection = new Connection();

export default connection;
Enter fullscreen mode Exit fullscreen mode

Now our code is much cleaner, and we can easily change the configurations if we need to.

But let's go deeper, let's use a base config that we can merge all our configurations in one place.

Let's install Mongez Config

yarn add @mongez/config
Enter fullscreen mode Exit fullscreen mode

Now let's create an index.ts file in our config directory.

// src/config/index.ts
import config from '@mongez/config';
import { databaseConfigurations } from './database';

config.set({
  database: databaseConfigurations,
});
Enter fullscreen mode Exit fullscreen mode

The config.set method can receive an object that contain all of our configurations, we'll group each configuration with a key, so our database key will be database.

Now we can use the config object to get the database configurations.

// src/database/connection.ts
import { MongoClient } from "mongodb";
import config from '@mongez/config';

export class Connection {
  /**
   * Mongo Client
   */
  public client?: MongoClient;

  /**
   * Connect to the database
   */
  public async connect() {
    const host = config.get("database.host", "localhost");
    const port = config.get("database.port", 27017);
    const username = config.get("database.username", "");
    const password = config.get("database.password", "");

    try {
      this.client = await MongoClient.connect(`mongodb://${host}:${port}`, {
        auth: {
          username: username,
          password: password,
        },
      });
      console.log("Connected!");
    } catch (error) {
      console.log(error);
    }
  }
}

const connection = new Connection();

export default connection;
Enter fullscreen mode Exit fullscreen mode

So let's see what we did here, we just replaced the import and used config from the package directory.

We can access any value from the config using config.get which can receive the key that we want, which will be under database, thanks to dot.notation support, we can access the nested keys directly by just writing the key with dot.notation, so the database config contains host we can access it directly database.host, the second argument is the default value, so if the key doesn't exist, it will return the default value, which is another important feature to be considered when working with low level code, the default value concept.

Calling our config

Now we created config/index.ts but it has not been imported in anywhere yet, let's import it in our src/index.ts at the top of it.

// src/index.ts
import './config';
//
Enter fullscreen mode Exit fullscreen mode

If we want to make it an alias, just add "config": "src/config/index.ts" to compilerOptions.paths in tsconfig.json file.

Authentication warning

As we mentioned earlier, database without authentication is not secure, so let's add authentication warning if user didn't add any username or password.

// src/database/connection.ts


  public async connect() {
    const host = config.get("database.host", "localhost");
    const port = config.get("database.port", 27017);
    const username = config.get("database.username", "");
    const password = config.get("database.password", "");

    try {
      this.client = await MongoClient.connect(`mongodb://${host}:${port}`, {
        auth: {
          username: username,
          password: password,
        },
      });
      console.log(
        "Connected!",        
      // 👇🏻 Warning message
        !username || !password
          ? "Your not making a secure authenticated connection!"
          : "",
      );
    } catch (error) {
      console.log(error);
    }
  }
Enter fullscreen mode Exit fullscreen mode

We added a new message that if the user has made a connection without username and password, it will show a warning message.

Colorful messages

We can use chalk to color our messages, let's install it.

yarn add chalk@4
Enter fullscreen mode Exit fullscreen mode

Please note that we are using version 4 of chalk, because version 5 is not compatible with typescript.

Now let's update our connection class.

// src/database/connection.ts
import config from "@mongez/config";
import chalk from "chalk";
import { MongoClient } from "mongodb";

export class Connection {
  /**
   * Mongo Client
   */
  public client?: MongoClient;

  /**
   * Connect to the database
   */
  public async connect() {
    const host = config.get("database.host", "localhost");
    const port = config.get("database.port", 27017);
    const username = config.get("database.username", "");
    const password = config.get("database.password", "");

    try {
      this.client = await MongoClient.connect(`mongodb://${host}:${port}`, {
        auth: {
          username: username,
          password: password,
        },
      });
      console.log(
        chalk.green("Connected!"),
        !username || !password
          ? chalk.red("Your not making a secure authenticated connection!")
          : "",
      );
    } catch (error) {
      console.log(error);
    }
  }
}

const connection = new Connection();

export default connection;
Enter fullscreen mode Exit fullscreen mode

Now we can see something like this if there is no username or password.

Database Connection

Conclusion

In this lesson, we learned how to create a configuration system for our application, and how to use it in our code.

🎨 Project Repository

You can find the latest updates of this project on Github

😍 Join our community

Join our community on Discord to get help and support (Node Js 2023 Channel).

🎞️ Video Course (Arabic Voice)

If you want to learn this course in video format, you can find it on Youtube, the course is in Arabic language.

💰 Bonus Content 💰

You may have a look at these articles, it will definitely boost your knowledge and productivity.

General Topics

Packages & Libraries

React Js Packages

Courses (Articles)

Latest comments (0)