# Node.JS module to retrieve configuration from environment variables

I don't like the idea of sprinkling process.env all over the place and wanted to abstract it out a bit. I'm new to Node and know there must be a better way to do a few things.

1. Not repeat the name 4 times (twice as a string and twice as a field)
2. Any cleaner way to create properties and centralize existence checks than how I've done it? Mind you, I am trying to keep this Node 4.3.2 compatible sans Babel transpilers to keep it simple and working in AWS Lambda's NodeJs environment.

// module

module.exports = {

}

var configError = function (keyName) {
console.error("ExternalVars error! Could not load a value for: "+keyName);
process.exit(1);
}

// TODO: extract repeated function?
Object.defineProperty(module.exports, 'SAMPLE_SECRET', {
get: function() {
if (!process.env.SAMPLE_SECRET)
configError('SAMPLE_SECRET');
else
return process.env.SAMPLE_SECRET;
}
});

Object.defineProperty(module.exports, 'SAMPLE_SECRET_MORE', {
get: function() {
if (!process.env.SAMPLE_SECRET_MORE)
configError('SAMPLE_SECRET_MORE');
else
return process.env.SAMPLE_SECRET_MORE;
}
});

// usage example

var externalvars = require('./config/externalvars.js');

var sampleSecret = externalvars.SAMPLE_SECRET;
var sampleSecretMore = externalvars.SAMPLE_SECRET_MORE;


Disclaimer: since I'm not familiar with export/import realm, my suggestion below might be too naive and not work. If so, rather than only downvoting, thanks in advance for a little comment pointing me to a resource which would enlight how and why I'm wrong.

That's said, with merely my pure JS skills, here is how I'd work:

var keys = [
'SAMPLE_SECRET',
'SAMPLE_SECRET_MORE'
];
keys.forEach(function(keyName) {
Object.defineProperty(module.exports, keyName, {
get: function() {
if (!process.env[keyName]) {
console.error(
"ExternalVars error! Could not load a value for: " + keyName
);
process.exit(1);
} else {
return process.env[keyName];
}
}
});
});

• This nicely removes the redundancy but for reasons I don't understand evaluates the getter without me calling it. For instance I set a value of process.env.SAMPLE_SECRET and then ask for it back and it tells me it can't find a value for SAMPLE_SECRET_MORE despite not asking for it.
– ss2k
Dec 4 '16 at 18:10
• @ss2k "evaluates the getter without me calling it": that's inherent to the way my proposed snippet works. And reading your comment I understand it doesn't exactly fits your need. In other words I believed you wanted to have something like a general configuration (hence my keys list), which would be early prepared for each registered key. Now you might consider replacing my keys.forEach(function(keyName) {...}); by function(keyName) {...} and invoke it when needed. BTW I realized my code was abruptly terminated, missing ); at the end. Corrected. Dec 4 '16 at 21:00
• I wasn't able to replace as you had suggested without a syntax error. Can you write out your alternate version?
– ss2k
Dec 6 '16 at 0:29
• @ss2k My "alternate version" is merely what I wrote in my previous comment. In other words, embed the Object.defineProperty() statement in a function, say processEnv(keyname), then call it when needed, e.g. processEnv(SAMPLE_SECRET). Dec 6 '16 at 10:25

Untested, but this should be equivalent to yours:

const requiredKeys = ['SAMPLE_SECRET', 'SAMPLE_SECRET_MORE']

const keyValues = requiredKeys.reduce((m,x) => {
if (!process.env[x]) {
console.error("ExternalVars error! Could not load a value for: "+keyName)
process.exit(1)
}
m[x] = process.env[x]
return m
}, {})

export default keyValues