|
| 1 | +# zero-config |
| 2 | + |
| 3 | +<!-- |
| 4 | + [![build status][build-png]][build] |
| 5 | + [![Coverage Status][cover-png]][cover] |
| 6 | + [![Davis Dependency status][dep-png]][dep] |
| 7 | +--> |
| 8 | + |
| 9 | +<!-- [![NPM][npm-png]][npm] --> |
| 10 | + |
| 11 | +<!-- [![browser support][test-png]][test] --> |
| 12 | + |
| 13 | +A zero configuration configuration loader |
| 14 | + |
| 15 | +## Example |
| 16 | + |
| 17 | +```js |
| 18 | +// config/common.json |
| 19 | +{ |
| 20 | + "port": 9001 |
| 21 | +} |
| 22 | +``` |
| 23 | + |
| 24 | +```js |
| 25 | +// config/production.json |
| 26 | +{ |
| 27 | + "redis": { |
| 28 | + "host": "localhost", |
| 29 | + "port": 6379 |
| 30 | + } |
| 31 | +} |
| 32 | +``` |
| 33 | + |
| 34 | +```js |
| 35 | +// server.js |
| 36 | +var fetchConfig = require('playdoh-server/config') |
| 37 | + |
| 38 | +var NODE_ENV = process.env.NODE_ENV |
| 39 | +var config = fetchConfig(__dirname, { |
| 40 | + dc: NODE_ENV === 'production' ? |
| 41 | + '/etc/playdoh/datacenter' : null |
| 42 | +}) |
| 43 | + |
| 44 | +var port = config.get("port") |
| 45 | +var redisConf = config.get("redis") |
| 46 | +var redisPort = config.get("redis.port") |
| 47 | +``` |
| 48 | + |
| 49 | +You can also call the process with |
| 50 | + `node server.js --port 10253` to change the config |
| 51 | + information from the command line |
| 52 | + |
| 53 | +## Docs |
| 54 | + |
| 55 | +### `var config = fetchConfig(dirname, opts)` |
| 56 | + |
| 57 | +```ocaml |
| 58 | +playdoh-server/config := (dirname: String, opts?: { |
| 59 | + argv?: Array<String>, |
| 60 | + dc?: String, |
| 61 | + blackList?: Array<String>, |
| 62 | + env?: Object<String, String> |
| 63 | +}) => { |
| 64 | + get: (keypath?: String) => Any, |
| 65 | + set: (keypath: String, value: Any) => void, |
| 66 | + __state: Object<String, Any> |
| 67 | +} |
| 68 | +``` |
| 69 | + |
| 70 | +`fetchConfig` takes the current __dirname as an argument, it |
| 71 | + assumes that there exists a config folder at `./config` in |
| 72 | + your project and it assumes there exists a `common.json` and a |
| 73 | + `NODE_ENV.json` for each environment. |
| 74 | + |
| 75 | +It returns you a `config` object with a `get(keypath)` method |
| 76 | + to fetch properties out of config. `get()` takes a keypath, |
| 77 | + i.e. `"prop.nested.someKey"`to get direct or nested properties |
| 78 | + in the config object. |
| 79 | + |
| 80 | +It's recommended you use `.get()` as in the future we will |
| 81 | + enable dynamic config properties through flipr support. |
| 82 | + |
| 83 | +### The config lookup algorithm |
| 84 | + |
| 85 | +The `fetchConfig()` function tries to fetch config from multiple |
| 86 | + locations and then deep merges the objects it finds together |
| 87 | + into a single object. |
| 88 | + |
| 89 | +Below are the sources it reads in order of least precendence. |
| 90 | + i.e. the later sources in the list overwrite the earlier ones |
| 91 | + |
| 92 | + - a `config/common.json` JSON file in your project |
| 93 | + - a `config/NODE_ENV.json` JSON file in your project |
| 94 | + - a `config/NODE_ENV.{datacenter}.json` JSON file in your |
| 95 | + project if you specificed a datacenter. |
| 96 | + - a `{ datacenter: '{datacenter}' }` literal if you |
| 97 | + specified a datacenter. |
| 98 | + - a `--config=/var/config/some-file.json` JSON file if you |
| 99 | + passed a command line argument called `--config` to the |
| 100 | + process. |
| 101 | + - a object literal based on command line arguments. i.e. if |
| 102 | + you pass `--foo='bar' --bar.baz='bob'` you will get |
| 103 | + `{ "foo": "bar", "bar": { "baz": "bob" } }` |
| 104 | + |
| 105 | +The config loader also uses `config-chain` for the actual |
| 106 | + loading logic so you can read [their docs][config-chain] |
| 107 | + |
| 108 | +#### `dirname` |
| 109 | + |
| 110 | +`dirname` is the directory that is the parent of the `config` |
| 111 | + directly. If you call `fetchConfig` in a file located in the |
| 112 | + root directory you can just pass `__dirname` as config lives |
| 113 | + at `./config`. |
| 114 | + |
| 115 | +If you require `fetchConfig` anywhere else like `./api/server.js` |
| 116 | + you will have to pass `path.join(__dirname, '..')` |
| 117 | + |
| 118 | +#### `opts` |
| 119 | + |
| 120 | +`opts` is an optional object, that contains the following |
| 121 | + properties. |
| 122 | + |
| 123 | +**Note** that `opts` is only optional in environments other then |
| 124 | + `"production`". If your `process.env.NODE_ENV` is set to |
| 125 | + `"production"` then you **MUST** specifiy `opts` and specify |
| 126 | + the `opts.dc` parameter. |
| 127 | + |
| 128 | +Running a production service without knowing how to load |
| 129 | + datacenter specific configuration is a bug. |
| 130 | + |
| 131 | +#### `opts.dc` |
| 132 | + |
| 133 | +`opts.dc` is either `null` or a string path to a file that |
| 134 | + contains the name of the datacenter. |
| 135 | + |
| 136 | +Say you have two datacenters, EC2-west and EC2-east. It's |
| 137 | + recommended that you have a file called `/etc/datacenter` |
| 138 | + that contains either the string `EC2-west` or `EC2-east`. |
| 139 | + |
| 140 | +This way any service can know what datacenter it is running |
| 141 | + in with a simple `cat /etc/datacenter`. |
| 142 | + |
| 143 | +Note that if you pass the dc config to `fetchConfig` then the |
| 144 | + config object will contain the `"datacenter"` key whose value |
| 145 | + is either `EC2-west` or `EC2-east` or whatever your datacenter |
| 146 | + names are. |
| 147 | + |
| 148 | +We will also load the file `config/production.EC2-west.json` |
| 149 | + and merge that into the config tree. |
| 150 | + |
| 151 | +#### `opts.argv` |
| 152 | + |
| 153 | +`opts.argv` is optional and probably not needed |
| 154 | + |
| 155 | +`fetchConfig` will read your process argv information using |
| 156 | + the [`minimist`][minimist] module. |
| 157 | + |
| 158 | +If you do not want `fetchConfig` to read global argv for you, |
| 159 | + you can pass in an `argv` object with keys like `'foo'` and |
| 160 | + `'bar.baz''` and values that are strings / numbers / booleans |
| 161 | + |
| 162 | +#### `opts.blackList` |
| 163 | + |
| 164 | +`opts.blackList` is an optional array of argv keys to blacklist. |
| 165 | + |
| 166 | +`fetchConfig` by default converts all command line arguments to |
| 167 | + configuration keys. If you want to pass a non config key |
| 168 | + command line argument like `--debug` or `--restart-fast`, etc. |
| 169 | + then you might want to add them to the `blackList` |
| 170 | + |
| 171 | +If your `opts.blackList` is `['debug']` then `config.get('debug')` |
| 172 | + will not resolve to the `--debug` command line argument. |
| 173 | + |
| 174 | +#### `opts.env` |
| 175 | + |
| 176 | +`opts.env` is optional and probably not needed. |
| 177 | + |
| 178 | +`fetchConfig` will read the env using `process.env`. The only |
| 179 | + property it reads is an environment variable called `NODE_ENV`. |
| 180 | + |
| 181 | +If you prefer to not have this variable configured through |
| 182 | + the environment or want to call it something else then you |
| 183 | + can pass in `{ NODE_ENV: whatever }` as `opts.env` |
| 184 | + |
| 185 | +#### `var value = config.get(keypath)` |
| 186 | + |
| 187 | +`config.get(keypath)` will return the value at a keypath. The |
| 188 | + `keypath` must be a string. |
| 189 | + |
| 190 | +You can call `config.get('port')` to get the port value. You |
| 191 | + can call `config.get('playdoh-logger.kafka.port')` to get |
| 192 | + the nested kafka port config option. |
| 193 | + |
| 194 | +#### `config.set(keypath, value)` |
| 195 | + |
| 196 | +`config.set(keypath, value)` will set a value at the keypath. |
| 197 | + |
| 198 | +You can call `config.set("port", 9001)` to set the port value. |
| 199 | + You can call `config.set("playdoh-logger.kafka.port", 9001)` to |
| 200 | + set then nested kafka port config option. |
| 201 | + |
| 202 | +## Installation |
| 203 | + |
| 204 | +`npm install zero-config` |
| 205 | + |
| 206 | +## Tests |
| 207 | + |
| 208 | +`npm test` |
| 209 | + |
| 210 | +## Contributors |
| 211 | + |
| 212 | + - Raynos |
| 213 | + |
| 214 | +## MIT Licenced |
| 215 | + |
| 216 | + [build-png]: https://secure.travis-ci.org/uber/zero-config.png |
| 217 | + [build]: https://travis-ci.org/uber/zero-config |
| 218 | + [cover-png]: https://coveralls.io/repos/uber/zero-config/badge.png |
| 219 | + [cover]: https://coveralls.io/r/uber/zero-config |
| 220 | + [dep-png]: https://david-dm.org/uber/zero-config.png |
| 221 | + [dep]: https://david-dm.org/uber/zero-config |
| 222 | + [test-png]: https://ci.testling.com/uber/zero-config.png |
| 223 | + [tes]: https://ci.testling.com/uber/zero-config |
| 224 | + [npm-png]: https://nodei.co/npm/zero-config.png?stars&downloads |
| 225 | + [npm]: https://nodei.co/npm/zero-config |
0 commit comments