npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

appyconfig

v1.5.3

Published

Read application configuration data from different sources in a unified way.

Downloads

5

Readme

appyconfig

Read and unify application configuration data from different sources.

Install

npm install appyconfig

Configuration

  1. Create a configuration tree in config.js that declares your configuration sources and options.
  2. Call resolveConfig() to resolve the configuration.
  3. Require/import your config.js wherever the config is needed.

Example

In your lib/config.js:

const { resolveConfig } = require('appyconfig');

// Define default values and the environment variables that will override them.
const config_tree = {
  "dbuser": {
    default: "root",
    env: "DB_USERNAME"
  },
  "dbpass": {
    env: "DB_PASSWORD"
  }
}

const config = resolveConfig(config_tree);

// Export your config.
module.exports = config;

Now require 'lib/config' from your app to get the global configuration.

const config = require('lib/config');

console.log(`Using db user #{config.dbuser}.`);

Data Sources

Examples of data sources are:

  • Hard coded default values
  • Environment variables
  • Command line arguments
  • YAML or JSON configuration file

Each of these data sources has a corresponding Loader class, and most have a key that will represent options in the configuration tree.

| Data source | Class | Key | Other considerations | |--- |--- |--- |--- | | Default values | DefaultValueLoader | default | Key is value to set | | Environment variables | EnvLoader | env | Key is the environment variable to fetch | | Command line arguments | CmdArgsLoader | cmdArg | Key is the command line option to retrieve | | JSON file | JsonLoader | N/A | Specify filename when instantiating JsonLoader | | YAML file | YamlLoader | N/A | Specify filename when instantiating YamlLoader | | .env file | DotenvLoader | dotenv | Specify .env file to loadKey is the name of the variable to fetch |

Default values

A config option with a default value must have a property named "default" whose value is the default.

Environment variables

A config option with an environment variable must have a property named "env" whose value is the name of the environment variable to read.

Command line arguments

See the Commander Example below.

JSON files

To read from JSON files, you will need to instantiate a new ConfigResolver and pass an instance of JsonLoader. The file will be read and the configuration will be merged in the order you provide to the ConfigResolver.

You do not need to add anything to the configuration tree for JSON files.

In config.js:

const config = resolveConfig(config_tree, [
  new JsonLoader(filename) // file to read.
]);

module.exports = config;

YAML files

Similar to JSON files, you will need to instantiate a new ConfigResolver and pass an instance of YamlLoader.

Configuration tree structure

Appyconfig expects the configuration tree to be an object with properties, where each property name is the name of the configuration option and its value is an object containing the parameters to use for different data sources.

Nested Values

If the value object itself contains objects, then it will be treated as a nested option. This is helpful for organizing your configuration.

// Nested values example
const config_tree = {
  "api": {  // api options
    "api_key": {
      //...
    },
    "api_secret": {
      //...
    }
  },

  "db": {   // database options
    "username": {
      //...
    },
    "password": {
      //...
    }
  }
}

Configuration Values

In the configuration tree, configuration options can be set to values of any type. If the value is not a simple type, then it must be enclosed in an array.

  const config_tree = {
    slogan: {         // String is a simple type
      default: "This is a cool app!"
    },
    logging: {        // Boolean is also a simple type
      default: true
    },
    db: {             // Object is enclosed in an array
      default: [
        { hostname: "localhost", port: 3425}
      ]
    }
    migrations: {     // Array is itself enclosed in an array
      default: [
        ["20210103", "20210224"]
      ]
    }
  };

Customizing the Configuration Resolution Order

By default when running resolveConfig(), appyconfig will use default config values (DefaultValueLoader) first, then override those values with environment variables (EnvLoader). This is equivalent to the following code:

const config = resolveConfig(config_tree, [
  new DefaultValueLoader,
  new EnvLoader
]);

You can choose to use different sources. For example, to fill the configuration with null values:

const config = resolveConfig(config_tree, [new NullLoader])

Dotenv

You can load a specific .env file and retrieve values in the same way that you retrieve environment variables.

# dotenv file
DB_USERNAME="MyUsername"
DB_PASSWORD="secret"

In your config.js:

const config = resolveConfig(config_tree, [new DotenvLoader("/approot/.env.production")]);

And in your config tree:

const config_tree = {
  "dbuser": {
    dotenv: "DB_USERNAME"
  },
  "dbpass": {
    dotenv: "DB_PASSWORD"
  }
}

If you are already parsing environment variables, you can instead load the dotenv file first, then continue to read environment variables with the 'env' key. In config.js:

const dotenv = require('dotenv').config();

Commander

If you are using Commander, appyconfig utilizes the preAction hook to grab global command line options.

This means the Command instance must be passed to resolveCommander() so that the hook can be installed. Command-line options will be extracted when the 'preAction' hook is executed (i.e. before actions are run).

Commander Example

In your lib/config:

const { ConfigResolver, DefaultValueLoader, EnvLoader, CmdArgsLoader } = require('appyconfig');

const config_tree = {
  // Define your config tree here.
  // The key for parsing command line args is cmdArgs, and it contains
  // the command line option key to retrieve from program.opts().
  mysetting: {
    default: "defaultValue",
    env: "MYSETTING",
    cmdArg: "mySetting" // --my-setting
  }
};

const resolver = new ConfigResolver();
const config = resolver.resolveConfig(config_tree, [
  new DefaultValueLoader,
  new EnvLoader,
  new CmdArgsLoader
]);

module.exports = { config, resolveCommander: resolver.resolveCommander };

In app.js:

const { Command } = require('commander');
const { resolveCommander } = require('lib/config');

const program = new Command();
resolveCommander(program);

// Note an action must be run to trigger option parsing.
program.action(() => {});

// Set up your program command line options here...

program.parse(process.argv);

Using the configuration:

const { config } = require('lib/config');

console.log(`My setting: ${config.mysetting}`);

To change the option on the command line:

node app.js --my-setting updated

Overlay Additional Configuration

If you want to merge the resolved configuration object with another data source after the fact, you can call resolveConfig(), passing in the existing configuration object and a new data source. Depending on your data source, you may need a different configuration tree from the one you created in lib/config.js:

const config = require('lib/config');
const { program } = require('commander');

// Grab a user configuration file from program arguments.
const userConfigFile = program.args[0];

// YamlLoader does not use the config tree, so it's okay to pass an empty object.
const newConfig = resolveConfig({}, new YamlLoader(userConfigFile), config);

// Do something with newConfig...