Author avatar

Lucas Bleme

Making Sure an App Can Read Configuration

Lucas Bleme

  • Sep 15, 2020
  • 13 Min read
  • 2,455 Views
  • Sep 15, 2020
  • 13 Min read
  • 2,455 Views
Configuration Management
Configuration Management Platforms
IT Infrastructure

Introduction

Every modern app needs to read configuration parameters. Information such as database connection URL, API endpoint, and staging/production DNS are good examples of things we often store in configuration parameters. There are different ways to read configuration, depending on where your configuration is stored and how your app needs to read it.

This guide will show you how your app can read configurations the right way by demonstrating the two most common approaches for it: reading configuration from the execution environment and reading configuration from an external config provider.

The examples demonstrated here uses the dotenv (.env) library when talking about reading config from the execution environment, and AWS SSM (Systems Manager Parameter Store) when talking about reading configuration from an external provider. But keep in mind that the practices and techniques demonstrated here are applicable in any other configuration management tools.

Reading from Environment Variables

One of the most popular tools used for storing and reading configurations is dotenv. It allows apps to read configurations that are stored in environment variables. It's pretty quick to set up, and is broadly used in development and production scenarios for all sorts of JavaScript apps.

Setting Up Dotenv

First, install dotenv using NPM by running this code at the root folder of your app:

1npm install dotenv
bash

Now, create the file that will store two configuration parameters: an API URL and a database URL. The file that dotenv provides for allowing you to store your configuration is called simply .env. Create it at the root folder of your project with the following content:

1API_URL=https://app.pluralsight.com/plans
2DATABASE_URL=postgresql://user:[email protected]:5432
.env

You can have as many config parameters as you want stored in this .env file.

Reading from Dotenv

Now, allow your app to read this configuration. To do so, you just need to require the dotenv module from inside your app, preferably in a file that is loaded before any other. In a Node.js app, this could be at the index.js file:

1require('dotenv').config();
javascript

This will make all your config parameters stored at the .env file available at any time in your app by just using the process.env call. Let's say you want to use the DATABASE_URL configuration value in your db.js file for example:

1import pg from 'pg';
2import dotenv from 'dotenv';
3
4const Pool = pg.Pool;
5
6// This variable will assume the value configured at the .env file
7const connectionString = process.env.POSTGRES_URL;
8
9const pool = new Pool({
10  connectionString
11});
javascript

Pretty simple isn't it? The thing is that, as you may know, if your app for some reason is not able to read the process.env.POSTGRES_URL configuration, your database operations will all fail. Let's check some ways to make sure your app is properly reading this configuration whenever you want it to.

Checking Config from Dotenv

An easy and useful technique that increases the visibility of your app's ability to read configurations is to check if one of your config parameters were properly read at the app's startup time, and print a message. At your Node index.js file, for example, you can simply check this by doing:

1import express from 'express';
2import dotenv from 'dotenv';
3
4const app = express();
5dotenv.config();
6
7
8app.listen(3000, () => {
9  // Checking if configuration is OK
10   if (process.env.API_URL) {
11      console.log('Configuration OK');
12   } else {
13      console.log('Error: Could not read configuration parameters')
14   }
15   
16   console.log('Server up and running');
17});
javascript

When starting the app, if it can properly read your configuration you should see the message:

Success message being shown when the app properly reads the configuration "Configuration OK" Success message when the app properly reads the configuration.

If for any reason the app is not able to read the configuration, the message "Error: Could not read configuration parameters" will be shown when it starts.

Automating the Config Check

Another way to make sure your app is successfully reading your configuration is to create a small unit test that checks the existence of the configuration. Using Jest, you can easily create this test. Your configuration.test.js file would look like this:

1require('dotenv').config();
2
3test('app can read configuration', () => {
4  const apiURL = process.env.API_URL;
5  const dbURL = process.env.DATABASE_URL;
6
7  expect(apiURL).not.toBeNull();
8  expect(apiURL).not.toBeUndefined();
9  expect(apiURL).toBeDefined();
10
11  expect(dbURL).not.toBeNull();
12  expect(dbURL).not.toBeUndefined();
13  expect(dbURL).toBeDefined();
14});
javascript

When running your test with the command npm jest at the root folder, you should see the success message if your app can successfully read the configuration parameters:

1PASS  ./configuration.test.js
2āœ“ app can read configuration (7ms)

Reading from a Centralized Repository

Another way to manage configuration in web apps is through external services where you store the configuration parameters into a centralized service. This way, all the apps that need to read configuration request for this external mechanism to provide the value of each config parameter. This approach is common in scenarios where there are too many apps that need to read a lot of different configurations. A microservices architecture is a good example of a scenario where you will probably want to use an externalized and centralized configuration strategy.

The next section will go over how to make sure your apps can read configurations from AWS SSM (Systems Manager), a service that allows you to create key/value parameters and securely access them.

Setting Up AWS SSM Parameters

Using a browser, navigate to the AWS console https://console.aws.amazon.com. In the top left menu, search for the service System Manager. Click the item found at the search bar:

AWS Console System ManagerAWS Console System Manager

When the service page opens, select Parameter Store.

**Application Management -> Parameter Store** menu item.Application Management -> Parameter Store menu item.

Now click Create parameter.

Click **Create parameter** button.Click Create parameter button.

To create the configuration parameter, insert the name of the parameter in the Name field and its value at the Value input.

Insert values for the new Parameter Inserting values for the new Parameter.

Next, click Create parameter.

And that's it. The parameter is now created and stored at the AWS Systems Manager.

Reading from AWS SSM

Now you need to access the parameter API_URL that was created using the AWS SDK, which allows you to interact with your AWS resources. First, install the AWS SDK using NPM by running the following command under the root folder of your JavaScript project:

1npm install aws-sdk

Next, get your AWS account credentials by selecting Your profile name -> My Security Credentialsa in the AWS console.

Click **My Security Credentials** menu item.Click My Security Credentials menu item.

On the next page, select Access keys -> Create New Access Key.

Click "Access keys -> Create New Access Key" Click Access keys -> Create New Access Key.

Copy the Access Key ID and Secret Access Key values and export the following environment variables in your local environment, replacing the values between < and > with the values you gathered from the previous step:

1$ export AWS_ACCESS_KEY_ID=<YOUR_KEY_ID>
2$ export AWS_SECRET_ACCESS_KEY=<YOUR_ACCESS_KEY_ID>

To read the configuration parameter API_URL, you need first to call the getCredentials function to properly configure the SDK, and then call the getParameter AWS SDK function from anywhere in your app.

At your api.js file, for example, you could do it like:

1import AWS from 'aws-sdk';
2
3AWS.config.getCredentials(function(err) {
4  // in case of credentials are not found
5  if (err) console.log(err.stack);
6});
7
8  const params = {
9     Name: 'API_URL',
10     WithDecryption: false
11  };
12
13  const ssm = new AWS.SSM();
14  ssm.getParameter(params, function(err, data) {
15     if (err) console.log(err, err.stack); // an error occurred
16     else     console.log('API_URL: ', data.Parameter.Value); // successful response
17  });
javascript

If everything goes right, you should see the https://api.myapp.com/plans value at your console, just like you configured for the API_URL parameter.

Checking Config from AWS SSM

In the same way, as demonstrated for the dotenv parameters, you can also display the configuration at startup time to make sure your app can properly read your external parameters. Just call the same getParameter function as early as possible in your app's code. Given a Node.js app, you could do it at your index.js file:

1import express from 'express';
2import AWS from 'aws-sdk';
3
4const app = express();
5
6app.listen(3000, () => {
7  AWS.config.getCredentials(function(err) {
8    if (err) console.log(err.stack);
9    // credentials not loaded
10    else {
11      console.log("AWS access ok");
12    }
13  });
14
15  const params = {
16    Name: 'API_URL',
17    WithDecryption: false
18  };
19  const ssm = new AWS.SSM();
20  ssm.getParameter(params, function(err, data) {
21    if (err) console.log(err, err.stack); // an error occurred
22    else     console.log('AWS SSM configuration ok: ', data); // successful response
23  });
24});
javascript

When your app starts, you should see the success message at the logs:

Success message when app properly reads the configuration from AWS SSM Success message is shown when the app properly reads the configuration from AWS SSM.

Automating the Config Check

You can also create a simple unit test to check if your app can read the external configuration. Using Jest, for example, you could have a file configuration.test.js that performs this check like this:

1import AWS from 'aws-sdk';
2
3test('app can read external configuration', () => {
4  AWS.config.getCredentials(function(err) {
5    if (err) console.log(err.stack);
6    // credentials not loaded
7  });
8
9 const params = {
10    Name: 'API_URL',
11    WithDecryption: false
12  };
13
14  const ssm = new AWS.SSM();
15  ssm.getParameter(params, function(err, data) {
16    if (err) {
17      throw new Error('Error reading external configuration');
18    } else {
19      const apiURL = data.Parameter.Value;
20
21      expect(apiURL).not.toBeNull();
22      expect(apiURL).not.toBeUndefined();
23    }
24  });
25});
javascript

If everything goes right, you should see the test passing when running npm jest at the root folder of your project:

1PASS  ./configuration.test.js
2āœ“ app can read external configuration (357ms)

Conclusion

Making sure your app can properly read configurations can be pretty simple. It's incredible how we often don't take the time to implement simple checks that could save us a lot of time in bug investigations and situations where everything goes wrong. Remember to take advantage of clear messages and automated unit tests to check if everything is okay.

I hope you have found good ideas on how to check if your app can read environment configurations and external parameters. Thanks for reading!