Skip to content

Contact sales

By filling out this form and clicking submit, you acknowledge our privacy policy.

Making Sure an App Can Read Configuration

Sep 15, 2020 • 13 Minute Read

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:

      npm install dotenv
    

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:

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

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:

      require('dotenv').config();
    

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:

      import pg from 'pg';
import dotenv from 'dotenv';

const Pool = pg.Pool;

// This variable will assume the value configured at the .env file
const connectionString = process.env.POSTGRES_URL;

const pool = new Pool({
  connectionString
});
    

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:

      import express from 'express';
import dotenv from 'dotenv';

const app = express();
dotenv.config();


app.listen(3000, () => {
  // Checking if configuration is OK
   if (process.env.API_URL) {
      console.log('Configuration OK');
   } else {
      console.log('Error: Could not read configuration parameters')
   }
   
   console.log('Server up and running');
});
    

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

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:

      require('dotenv').config();

test('app can read configuration', () => {
  const apiURL = process.env.API_URL;
  const dbURL = process.env.DATABASE_URL;

  expect(apiURL).not.toBeNull();
  expect(apiURL).not.toBeUndefined();
  expect(apiURL).toBeDefined();

  expect(dbURL).not.toBeNull();
  expect(dbURL).not.toBeUndefined();
  expect(dbURL).toBeDefined();
});
    

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:

      PASS  ./configuration.test.js
✓ 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:

When the service page opens, select Parameter Store.

Now click Create parameter.

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

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:

      npm install aws-sdk
    

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

On the next page, select 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:

      $ export AWS_ACCESS_KEY_ID=<YOUR_KEY_ID>
$ 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:

      import AWS from 'aws-sdk';

AWS.config.getCredentials(function(err) {
  // in case of credentials are not found
  if (err) console.log(err.stack);
});

  const params = {
     Name: 'API_URL',
     WithDecryption: false
  };

  const ssm = new AWS.SSM();
  ssm.getParameter(params, function(err, data) {
     if (err) console.log(err, err.stack); // an error occurred
     else     console.log('API_URL: ', data.Parameter.Value); // successful response
  });
    

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:

      import express from 'express';
import AWS from 'aws-sdk';

const app = express();

app.listen(3000, () => {
  AWS.config.getCredentials(function(err) {
    if (err) console.log(err.stack);
    // credentials not loaded
    else {
      console.log("AWS access ok");
    }
  });

  const params = {
    Name: 'API_URL',
    WithDecryption: false
  };
  const ssm = new AWS.SSM();
  ssm.getParameter(params, function(err, data) {
    if (err) console.log(err, err.stack); // an error occurred
    else     console.log('AWS SSM configuration ok: ', data); // successful response
  });
});
    

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

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:

      import AWS from 'aws-sdk';

test('app can read external configuration', () => {
  AWS.config.getCredentials(function(err) {
    if (err) console.log(err.stack);
    // credentials not loaded
  });

 const params = {
    Name: 'API_URL',
    WithDecryption: false
  };

  const ssm = new AWS.SSM();
  ssm.getParameter(params, function(err, data) {
    if (err) {
      throw new Error('Error reading external configuration');
    } else {
      const apiURL = data.Parameter.Value;

      expect(apiURL).not.toBeNull();
      expect(apiURL).not.toBeUndefined();
    }
  });
});
    

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

      PASS  ./configuration.test.js
✓ 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!