Cleanest way to declare env vars with Express - javascript

I'm trying to find out there the best solution about how to store environment vars for Node using Express. Many tutorials suggest to move the data into a .json file, here is an example but the don't config environment vars, they define new vars such as:
{
"test": {
"facebook_app_id": "facebook_dummy_dev_app_id",
"facebook_app_secret": "facebook_dummy_dev_app_secret",
},
"development": {
"facebook_app_id": "facebook_dummy_dev_app_id",
"facebook_app_secret": "facebook_dummy_dev_app_secret",
},
"production": {
"facebook_app_id": "facebook_dummy_prod_app_id",
"facebook_app_secret": "facebook_dummy_prod_app_secret",
}
}
The problem I've find to this approach is that I can't define vars in it, because all elements must be inside double quotes ( " ) so I can't do:
{
process.env.PORT = 3000,
process.env.NODE_APP = XXX
....
}
I've tried to do some tricky things like defining a .js file and store there the vars, something like this:
module.exports = {
env: {
USER:"www-data",
NODE_ENV:"development",
PORT:"3002",
....
LOG_FILE:"error.log"
}
}
In this case, I have not found the way to use those vars inside env, something like:
module.exports = {
env: {
...
process.env.APP_NAME:"application.name",
process.env.NODEJS_DIR:"/var/nodejs",
process.env.APP_DIR: `${this.NODEJS_DIR}/${this.APP_NAME}/current`, //Not working
process.env.APP_DIR:process.env.NODEJS_DIR}/${this.APP_NAME}/current`, //Not working, and verbose, ugly code
....
}
}
Is there a better way to solve this?
Thanks

You can use dotenv module to achieve this.
So in your root directory, create 2 files (depending on how many different environments you might have) named development.env and production.env
In your app, do this:
var env = process.env.NODE_ENV || 'development';
require('dotenv').config({
path: './' + env + '.env'
});
Then you could access all the environment variables you have defined in the respective env file.

Something like this you are looking for.
app.configure('production', function(){
// production env. specific settings
});

As another example of forming the config file
// config file in /config/general.js
var path = require('path'),
rootPath = path.normalize(__dirname + '/..'),
env = process.env.NODE_ENV || 'development';
if (env == 'development') {
process.env.DEBUG = 'http';
}
var config = {
development: {
name : 'development',
root: rootPath,
port: 3000
},
production: {
name : 'prod',
root: rootPath,
port: 3000
}
};
module.exports = config[env];

Think about the dev-ops team, how they will deploy your software? They won't touch the code, and the configuration file should not contain any logic. So the .js file containing configurations is wrong. You have to provide them an interface to configure the execution. That may be a parameter, or if the configuration is complex, then it should be extracted to a configuration file.
My approach is to load app.json by default. If the dev-ops engeneer provides NODE_ENV=customenv, then load app.customenv.json configuration file. This way the .json file won't expose non-relevant development configurations to the users.
APP_NAME is not part of the environment, but part of your software configuration. This parameter should be configured in the .json configuration file.
Directories can be relevant to the software directory, it defined in the __dirname variable.
The app.json file should be loaded by a configuration module. You can use one of the open-source projects available, for example nconf.

Related

Set environment variables outside of pages dir in nextjs?

Is there a way to set env variables outside of a pages directory in NextJS? I have a util function that provides the base API route in one place. However, since this is a util function it's not defined on a page. I'd like to avoid having to create a getStaticProps on every page to get my private env variables if possible.
Any thoughts?
utils/index.ts (not on a nextJS page)
export const apiAddress =
process.env.NEXT_PUBLIC_CURRENT_ENV === 'PRODUCTION'
? process.env.PROD_API
: process.env.DEV_API;
...
I had a similar issue where I couldn't access my env vars in the nextjs application.
The solution was to read them in the next.config.js and pass them implicitly.
My example loads the environment from /environments/env.development but you can use any location you want.
So my next next.config.js looks like this:
const path = require('path')
const { parsed: localEnv } = require('dotenv-safe').config({
allowEmptyValues: false,
path: path.resolve(__dirname, `environments/.env.development`),
})
const nextConfig = {
env: localEnv,
}
module.exports = nextConfig
You should be able to access the ENV vars in your .env file like usually:
process.env.YOUR_VARIABLE
Additionally
Based on environment, you can use a predefined ENV var from your package.json as well which lets you load the right file for your environment.
In your package.json define sth. like that in scriptssection:
"dev:development": "ENV=development node server.js",
"dev:staging": "ENV=staging node server.js"
...
Then you have access to the ENV var and can use it directly for your purposes in next.config.js.
Based on example above:
path: path.resolve(__dirname, `environments/.env.${process.env.ENV}`),

Simple and elegant way to override local file If exists?

Looking for elegant and simple solution to have "local configuration override" files.
The idea is to be able to have local configuration that will not ask to be added to git repository every time.
For that I need to include local.config.js if it exists.
I have global app configuration in config.js with configuration like
export const config = {
API_URL="https://some.host",
}
and config.local.js
export const config = {
API_URL="https://other.address",
}
there's .gitignore:
config.local.js
Difficulty:
I do not want to add a node module to project just for this one thing. I believe there should be an elegant way to do this in one or few lines, but have not found any so far.
Things that I tried:
1.
try {
const {
apiUrl: API_URL,
} = require('./config.local.js');
config. API_URL =apiUrl;
} catch (e) {
}
require does not work inside try{} block.
2.
const requireCustomFile = require.context('./', false, /config.local.js$/);
requireCustomFile.keys().forEach(fileName => {
requireCustomFile(fileName);
});
does not work.
3.
export const config = require('./config.local.js') || {default:'config = {...}'}
does not work.
4.
Using .env and settings environment variable: I need to override whole array of configuration values. Not one by one.
This solution uses process.argv. It is native to node as documented here and does not use .env
It inspects the command values used to start the app. Since these should be different between your local and production environments, it's an easy way to switch with no additional modules required.
command prompt to start your node app:
(this might also be in package.json and incurred via npm start if you're using that approach.)
$ node index.js local
index.js of your node app:
var express = require('express');
var config = require('./config');
if (process.argv[2] === 'local') {
// the 3rd argument provided at startup (2nd index) was 'local', so here we are!
config = require('./config_local');
}
var app = express();
// rest of owl…

How to set an environment variable in config.js of a node.js microservice?

I have a node.js application built using graphql. I need to check an 'environment variable' to see what environment I'm on (development, testing, production). Based on that environment, I need to set a url. I think I have a vague idea of what I need but don't know how to accomplish it.
Currently my config.js file looks something like this:
const configuration = convict({
env: {
format: ['development', 'testing', 'production'],
default: 'development',
arg: 'nodeEnv',
env: 'NODE_ENV'
}
const env = configuration.get('env');
configuration.loadFile(`./config/${env}.json`);
configuration.validate({allowed: 'strict'});
module.exports = configuration.getProperties();
)};
And then in a separate file where I actually need to set the url based on the environment, I need to do so based on the kind of environment (development, test or production) that I'm on. The code in that file would be:
If(env=='development'){
const url = 'abc.def.com/xxx/yyy/zzz/graphql';
}
Else If (env == 'testing'){
const url = 'xxx.yyyy.com/abc/def/ghi/graphql';
}
Else{
const url = '123.abc.com/cdc/def/hhh/graphql';
}
I tried to console.log the env value but when I try the following:
console.log( env );
I get an error: Reference error: env is not defined.
Can someone point me to what I'm missing/doing wrong to access the env variable?
You can access them like this:
process.env.VARIABLE_NAME

Setup app production and developent mode in node.js

In my node app, I want to set production and development in my config.js file.
For that I have all most set all thing but I'm still missing something.
I want to get config data like database credential from config file based on my development mode. If I upload on live then app will use live cred. On other hand if I used local then it should be use local cred.
module.exports = function () {
console.log("Process env is ::: ", process.env.NODE_ENV);
if (process.env.NODE_ENV == 'production') {
return {
db : {
host:'localhost',
batabase:'dbname',
username:'',
password:''
}
}
} else {
return {
db : {
host:'localhost',
batabase:'dbname',
username:'',
password:''
}
}
}
};
I have taken ref from this answer
Just try this way.
module.exports = (function () {
process.env.NODE_ENV='development';
if(process.env.NODE_ENV === 'production'){
// Config data of Live
}else{
//Config data of Local
}
})()
This works for me. :)
process.env refers to the Environment Variables exists at the time you start you nodejs app . (it's part of the os)
When you deploy to cloud , usually it's handled for you already (process.env.NODE_ENV = production) .
Some cloud providers even give you the option to control it via a GUI .
But for local environment , you can use .dotenv package . (https://github.com/motdotla/dotenv)
With this package you create a .env file at the top of your project ,
and just write down NODE_ENV = local/staging/production
Please note that you can always run in shell:
export NODE_ENV=production
(WATCH FOR WHITESPACES !)
before you start you nodejs app which will also give you the effect
of controlling process.env
Using the config files in other files, just by requiring it .
const config = require('path/to/config.js');
then config.data.host will be changed depend on the NODE_ENV

Make Node server.js file safer by removing security information

I have a public git[hub] project, and am now ready to switch it from development to production. We are in the research field, so we like to share our code too!
I have a server.js file that we start with node server.js like most tutorials.
In it, there is connection information for the SQL server, and the location of the HTTPS certificates. It looks something like this:
var https = require('https');
var express = require('express');
var ... = require('...');
var fs = require('fs');
var app = express();
var Sequelize = require('sequelize'),
// ('database', 'username', 'password');
sequelize = new Sequelize('db', 'uname', 'pwd', {
logging: function () {},
dialect: 'mysql',
…
});
…
var secureServer = https.createServer({
key: fs.readFileSync('./location/to/server.key'),
cert: fs.readFileSync('./location/to/server.crt'),
ca: fs.readFileSync('./location/to/ca.crt'),
requestCert: true,
rejectUnauthorized: false
}, app).listen('8443', function() {
var port = secureServer.address().port;
console.log('Secure Express server listening at localhost:%s', port);
});
In PHP you can have the connection information in another file, then import the files (and therefore variables) into scope to use. Is this possible for the SQL connection (db, uname, pwd) and the file locations of the certs (just to be safe) so that we can commit the server.js file to git and ignore/not follow the secret file?
You can do this in a lot of different ways. One would be to use environment variables like MYSQL_USER=foo MYSQL_PASSWD=bar node server.js and then use process.env.MYSQL_USER in the code.
You can also read from files as you have suggested. You can do require("config.json") and node will automatically parse and import the JSON as JavaScript constructs. You can then .gitignore config.json and perhaps provide an example.config.json.
If you want to support both of these at once there is at least one library that allows you to do this simply: nconf.
You can always just store the configuration information in a JSON file. Node natively supports JSON files. You can simply require it:
var conf = require('myconfig.json');
var key = fs.readFileSync(conf.ssl_keyfile);
There are also 3rd party libraries for managing JSON config files that add various features. I personally like config.json because it allows you to publish a sample config file with empty values then, without modifying the sample config file, you can override those values using a .local.json file. It makes it easier to deal with config files in repos and also makes it easier to publish changes to the config file.
Here is great writeup about how you should organise your deployments
Basically all application critical variables like db password, secret keys, etc., should be accessible via environment variables.
You could do something like this
// config.js
const _ = require('lodash');
const env = process.env.NODE_ENV || 'development';
const config = {
default: {
mysql: {
poolSize: 5,
},
},
development: {
mysql: {
url: 'mysql://localhost/database',
},
},
production: {
mysql: {
url: process.env.DB_URI,
},
},
};
module.exports = _.default(config.default, config[env]);
// app.js
const config = require('./config');
// ....
const sequelize = new Sequelize(config.mysql.url);
Code is not perfect, but should be enough to get the idea.

Categories