Skip to content

Commit

Permalink
Merge pull request #3 from tusharmath/reading-env-variables
Browse files Browse the repository at this point in the history
Reading env variables
  • Loading branch information
tusharmath authored Jan 10, 2018
2 parents 4723eb7 + fbef4d0 commit 65a1f6c
Show file tree
Hide file tree
Showing 20 changed files with 309 additions and 111 deletions.
50 changes: 41 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,19 @@ node-config-ts

A simple configuration manager for typescript based projects.

## Table of contents
1. [Usage](#usage)

2. [Configuration](#configuration)

a. [Using Files](#using-files)

b. [Using Environment Variables](#using-environment-variables)

c. [Using Commandline Params](#using-commandline-params)

3. [Differences With Node Config](#differences-with-node-config)

## Usage

1. Install package
Expand Down Expand Up @@ -43,7 +56,16 @@ A simple configuration manager for typescript based projects.
console.log(config) // logs the config data from default.json
```

## Directory Structure
## Configuration
The configs are merged in the following order of priority —

1. Commandline params
2. Environment variable
2. User specific config file
3. Deployment specific config file
4. Environment specific config file

### Using files
Configurations are loaded via config files that are written in JSON format for now. A typical project looks like this —

```
Expand All @@ -63,7 +85,7 @@ root/
└── sara.json
```
There are three directories in which a project can have configurations — `deployment`, `env` and `user`. These directories can have multiple files inside them and based on the environment variables an appropriate config file is selected for overriding the base `default.json`. For instance if the `NODE_ENV` variable is set to `production` the `env/production.json` configuration will be merged with `default.json`. Similarly if `DEPLOYMENT` env variable is set to `staging.example.com` then `deployment/staging.example.com.json` is merged with the other configs. Here is a table for environment to directory mapping —
There are three directories in which a project can have configurations — `deployment`, `env` and `user`. These directories can have multiple files inside them and based on the environment variables an appropriate config file is selected for overriding the base `default.json`. For example if the `NODE_ENV` variable is set to `production` the `env/production.json` configuration will be merged with `default.json` and override default values with its own. Similarly if `DEPLOYMENT` env variable is set to `staging.example.com` then `deployment/staging.example.com.json` is merged with the other configs. Here is a table for environment to directory mapping —
| **process.env** | **directory** |
Expand All @@ -72,16 +94,25 @@ There are three directories in which a project can have configurations — `depl
| DEPLOYMENT | /config/deployment |
| USER | /config/user |
## Configuration Priority
### Using environment variables
Whenever the value is prefixed with the letters `@@` **node-config-ts** automatically looks for an environment variable with that name. For example —
The configs are merged in the following order of priority —
```json
// default.json
{
"port": "@@APP_PORT"
}
```
In the above case automatically the value of `port` is set to the value that's available inside the environment variable `PORT`.

1. Commandline
2. User
3. Deployment
4. Environment
```bash
export APP_PORT=3000
node server.js // server started with config.port as 3000
```

The command line arguments can override all the configuration params. This is useful when you want to start a node server by passing the port externally —
### Using commandline params

The command line arguments can override all the configuration params. This is useful when you want to start a node server by passing the port externally —

```bash
node server.js --port 3000
Expand All @@ -94,6 +125,7 @@ In the above case even if the `default.json` has a port setting of `9000` the cl
"port": 9000
}
```

## Differences with node-config
1. **No reserved words:** With [node-config] you can not use a certain set of [reserved words] in your configuration. This is an unnecessary restriction and `node-config-ts` doesn't have it.
2. **Simpler API:** Instead of using methods such as `config.get('xxx')` in `node-config` you can simply use the exported `config` object.
Expand Down
4 changes: 2 additions & 2 deletions index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
* Created by tushar on 30/12/17.
*/

import {loadAllConfigs} from './src/load-all-configs'
import {mergeAllConfigs} from './src/mergeAllConfigs'

export const config = loadAllConfigs(process) as Config
export const config = mergeAllConfigs(process) as Config
109 changes: 106 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@
"cz-conventional-changelog": "^2.1.0",
"mocha": "^4.1.0",
"semantic-release": "^11.0.2",
"typescript": "^2.6.2"
"typescript": "^2.6.2",
"ts-node": "^4.1.0"
},
"config": {
"commitizen": {
Expand Down
File renamed without changes.
File renamed without changes.
15 changes: 0 additions & 15 deletions src/load-all-configs.ts

This file was deleted.

3 changes: 1 addition & 2 deletions src/load-cli-configs.ts → src/loadCliConfigs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,5 @@ import * as R from 'ramda'
* @return {{cliConfig: any}}
*/
export const loadCLIConfigs = (process: any) => {
const cliConfig = R.omit(['_'], minimist(process.argv))
return {cliConfig}
return R.omit(['_'], minimist(process.argv))
}
2 changes: 1 addition & 1 deletion src/load-file-configs.ts → src/loadFileConfigs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
*/
import moduleExists = require('module-exists')
import * as R from 'ramda'
import {configPaths} from './config-paths'
import {configPaths} from './configPaths'

/**
* Loads the configs provided in the {ConfigPaths}
Expand Down
19 changes: 19 additions & 0 deletions src/mergeAllConfigs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/**
* Created by tushar on 30/12/17.
*/
import R = require('ramda')
import {loadCLIConfigs} from './loadCliConfigs'
import {loadFileConfigs} from './loadFileConfigs'
import {replaceWithEnvVar} from './replaceWithEnvVar'
import {mergeFileConfigs} from './mergeFileConfigs'

/**
* Loads all the configs from files and cli and merges them.
*/
export const mergeAllConfigs = R.converge(R.mergeDeepRight, [
R.converge(replaceWithEnvVar, [
R.compose(mergeFileConfigs, loadFileConfigs),
R.identity
]),
loadCLIConfigs
])
12 changes: 2 additions & 10 deletions src/merge-configs.ts → src/mergeFileConfigs.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,16 @@
import * as R from 'ramda'

export type ConfigSources = {
defaultConfig: any
envConfig: any
deploymentConfig: any
userConfig: any
cliConfig: any
}
/**
* Merges the configs in the following order —
* defaultConfig < envConfig < deploymentConfig < userConfig < cliConfig
* @param {ConfigSources} configs
* @return {any}
*/

export const mergeConfigs = (configs: ConfigSources) => {
export const mergeFileConfigs = (configs: {[key: string]: any}) => {
return R.reduce(R.mergeDeepRight, configs.defaultConfig, [
configs.envConfig,
configs.deploymentConfig,
configs.userConfig,
configs.cliConfig
configs.userConfig
])
}
17 changes: 17 additions & 0 deletions src/replaceWithEnvVar.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/**
* Created by tushar on 10/01/18.
*/

import * as R from 'ramda'

const getVarName = R.replace('@@', '')
const hasEnvVar = R.test(/^@@.*$/)
export const replaceWithEnvVar = <T>(baseConfig: T, process: any) => {
const itar: any = R.map((value: any) => {
if (R.is(Object, value)) return itar(value)
if (R.is(String, value) && hasEnvVar(value))
return process.env[getVarName(value)]
return value
})
return itar(baseConfig)
}
2 changes: 1 addition & 1 deletion test/config-paths.test.ts → test/configPaths.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* Created by tushar on 30/12/17.
*/
import * as assert from 'assert'
import {configPaths} from '../src/config-paths'
import {configPaths} from '../src/configPaths'

describe('config-paths', () => {
describe('default', () => {
Expand Down
Loading

0 comments on commit 65a1f6c

Please sign in to comment.