16-Nodejs Course 2023: Application Configurations
Hasan Zohdy
Posted on October 31, 2022
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',
};
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/*"]
}
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;
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
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,
});
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;
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';
//
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);
}
}
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
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;
Now we can see something like this if there is no username or password.
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
- Event Driven Architecture: A Practical Guide in Javascript
- Best Practices For Case Styles: Camel, Pascal, Snake, and Kebab Case In Node And Javascript
- After 6 years of practicing MongoDB, Here are my thoughts on MongoDB vs MySQL
Packages & Libraries
- Collections: Your ultimate Javascript Arrays Manager
- Supportive Is: an elegant utility to check types of values in JavaScript
- Localization: An agnostic i18n package to manage localization in your project
React Js Packages
Courses (Articles)
Posted on October 31, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.