Changing Express constant based on URL (ie localhost vs production) - node.js

I'm fairly new to node and express...
I have a constant I set in my Node/Express application for "Domain". I'm constantly switching between localhost and the actual url when I switch between development and production.
I'm trying to figure out how I can automatically test the URL so that when the code is read on the server (ie actual domain url vs localhost) that it sets the proper domain url.
Here is my code:
function define(name, value) {
Object.defineProperty(exports, name, {
value: value,
enumerable: true
});
}
define("DOMAIN", "http://www.actual_domain.com");
// define("DOMAIN", "http://localhost:3000");
Anyone have a simple solution for this?
Thanks!!

there is many solutions for this, but usually this is done by environment variables, depends on your platform, but, in Linux systems, you do the following in your shell
export ENV_URL="http://www.example.com"
and to make sure its exported successfully
echo $ENV_URL
and in your code you do
const base_url = process.env.ENV_URL || "http://www.default.com";
in your local machine you set the ENV_URL to localhost or whatever you prefer, and in your server you set it to your actual URL.
or you could simply have many configuration files and you can determine the appropriate one by the environemnt variable like
export ENV=PROD
and in your code you can load the prod configuration file that contains your environment configurations.

The de facto way to do this sort of thing is through environment variables. Have a look at 12factor.net for a load of best practices, but in general you want to put differences in the environment into environment variables, then read those variables at runtime.

Related

How to use node package dotenv to access local development environment variables in Red Hat OpenShift application?

I'm revisiting a project which hasn't been updated for a while.
In production/online environment, it uses environment variables defined at:
openshift online console > applications > deployments > my node app > environment
In development/offline environment, it uses environment variables defined at:
./src/js/my_modules/local_settings (this file is ignored by .gitignore)
The code looks something like:
// check which environment we are in
if (process.env.MONGODB_USER) {
var online_status = "online";
}
else {
var online_status = "offline";
}
// if online, use environment variables defined in red hat openshift
if (online_status === 'online') {
var site_title = process.env.SITE_TITLE;
var site_description = process.env.SITE_DESCRIPTION;
//etc
}
// if offline, get settings from a local file
else if (online_status === 'offline') {
var local_settings = require('./src/js/my_modules/local_settings');
var site_title = local_settings.SITE_TITLE;
var site_description = local_settings.SITE_DESCRIPTION;
// etc
}
I would like to install the dotenv package in my local project repo via:
npm install dotenv
So that I can:
Have my local settings in a .env file in the root of my project (ignored in .gitignore)
Be able to use process.env.SOME_VARIABLE rather than local_settings.SOME_VARIABLE
Get rid of some if/else blocks as both scenarios would point to process.env.SOME_VARIABLE
I'm a bit confused as to how this would effect the online environment.
Seeing as both production/online and development/offline environments would use:
var some_variable = process.env.SOME_VARIABLE_HERE
would the application automatically know to:
Look at the local .env file when in development?
Look at the Red Hat environment variables when in production?
And would adding the required instantiation at the beginning of the server-side file:
require('dotenv').config()
somehow make Red Hat OpenShift freak out (as it seems to already have its own 'things' in place to resolve references to process.env.SOME_VARIABLE_HERE to the relevant values defined in the OpenShift console)?
To have a file by any environment (.dev .staging .prod) into the source code repository or manually in the server (it those are in .gitignore) worked for long time, but now it goes against to the devops.
The clean way is to use environment variables but managed remotely and obtained at the start of your application.
How it works?
Basically your apps don't read or need a file (.env .properties, etc) with variables anymore. It loads them from a remote http service.
Not intrusive
In this approach, you don't need specific languages variables (nodejs in your case). You just need to prepare your app to use environment variables. Your application don't care where the variables come from, just needs to be available at operative system level.
To achieve that, you just need to download the variables using a simple shell code or a very basic algorithm (http invocation) in your favorite language.
After that, after the start of your app, variables are ready to use at the most basic level.
var site_title = process.env.SITE_TITLE;
This approach is not intrusive because your app don't need something complex like library or algorithm in some programing language. Just needs the environment variables.
Intrusive
Same as previous alternative but instead to read the variables direct from environment system, you should use or create a class/module in your language. This offer your the variables you need:
var site_title = VariablesManager.getProperty("SITE_TITLE");
VariablesManager at the startup must have consumed the variables from a remote service (http) and the store them to offer them to whoever needs it through getProperty method.
Also this VariablesManager usually has a feature called hot-reload which at intervals, update the variables consuming the remote variables manager. With this, if your application is running in production with real users and some variable needs to be updated, you just need to change it in the variables manager. Automatically your app will load the new values, without restart or touching your app
This approach is intrusive because you need to load advanced libraries in some programing language or create it.
Devops
Your application just needs a few properties or settings related to the consume of remote variables. For example: variables of acme-web-staging:
remote_variables_manager = https://variables.com/api
application_id = acme-web-staging
secure_key = *****
You could hide the secure key and parametrize the application_id using environment variables (created in the platform console)
remote_variables_manager = https://variables.com/api
application_id = ${application_id}
secure_key = ${remote_variables_manager_key}
Or if you want one variable manager by each environment
staging
remote_variables_manager = https://variables-staging.com/api
application_id = acme-web
secure_key = *****
production
remote_variables_manager = https://variables-staging.com/api
application_id = acme-web
secure_key = *****
Variables manager
This concept was introduced many years ago. I used with java. It consist in a web application with features like:
secure login
create applications
create variables of an application
crypt sensitive values
publish http endpoints to download or query the variables by application
Here a list of some ready to use alternatives:
Configurator
Nodejs & mysql solution. I developed this and I use it in various projects.
Doppler
zookeeper
http://www.therore.net/java/2015/05/03/distributed-configuration-with-zookeeper-curator-and-spring-cloud-config.html
Spring Cloud
https://www.baeldung.com/spring-cloud-configuration
This is a java spring framework functionality in which you can create properties file with configurations and configure your applications to read them.
Consul
Consul is a service mesh solution providing a full featured control plane with service discovery, configuration, and segmentation functionality.
doozerd, etcd
In your specific case
Don't use dot-env
Use pure process.env.foo
Deploy a remote variables manager in your openshift infraestructure
Create just one variable in your openshift web console: APP_ENVIRONMENT
In your code at the start, do something like this:
if (process.env.APP_ENVIRONMENT === "PROD")
//get variables from remote service using
//some http client like axios, request, etc
//then inject them to your process.env
process.env.site_url = remoteVariables.site_url
else
//we are in local developer workspace
//so, nothing complex is required
//developer should inject manually
//before the startup: npm run start or dev
//export site_url = "acme.com"
If you can configure an execution of a shell script before the start of your openshift app, you could load and expose the variables at that stage and the previous snippet would not be necessary because the variables will be ready to be retrieved using process.env directly in your app

Handle multiple environments variables in .env NodeJs

Suppose I have a .env file like these:
#dev variable
PORT=3000
#production
PORT=3030
And I get these variables using process.env, how can I manage to sometimes use the dev variable and other times the Production variable
You can create multiple .env files like .dev.env, .prod.env, and load them based on NODE_ENV. using this
Storing configuration in environment variables is the way to go, and exactly what is recommended by the config in the 12-Factor App, so you're already starting with the right foot.
The values of these variables should not be stored with the code, except maybe the ones for your local development environment, which you can even assume as the default values:
port = process.env.PORT || '3000';
For all other environments, the values should be stored in a safe place like Vault or AWS Secrets Manager, and then are only handled by your deployment pipeline. Jenkins, for example, has a credentials plugin to handle that.

how can i get dynamic url in nodejs? (mernstack)

hi im trying to make forgot password/reset password service.
let me show you the logic of this service.
(simply, send email in react(localhost:3000/forgotPassword) -> click link in email -> route to localhost:3000/resetPassword)
1.send email in frontend
The content is to write down the email of the account you joined.
2.email
비밀번호 리셋하기 <- this is direct to http://localhost:3000/resetPassword
3.forgotPassword.js in node.js
Here, I want to change resetURL(http://localhost:3000/resetPassword) to dynamic URL. Because I will distribute this soon.
3.package.json in react
I was able to do api communication from react to node by specifying proxy here, but /api/resetPassword does not work in node.
To sum up, I want to use the code used by React on the node as well. Like this.
You are looking to environmentalise your configuration.
You could do it through an environment variable, like this:
const baseURL = process.env.BASE_URL || 'http://localhost:3000'
const resetURL =`${baseURL}/resetPassword`
If you use the dotenv package, you can support configuration through environment variables or from a .env file.
If I understand correctly, your interested in setting up a dynamic variable for the url in your react app. Try just setting an environment config file, either a file for each environment you are developing in (i.e., Dev, QA, PROD) or a single file with multiple shared Env variables. You can even add an env variable to your package.json file for example.
NOTE the approach below would work for linux and mac, but not windows
please use the resources below for more information. This approach has been made available for react-scripts#0.9.0 and higher.
{
"scripts": "APP_URL=http://localhost:300 npm start"
}
Resources:
https://medium.com/#trekinbami/using-environment-variables-in-react-6b0a99d83cf5
https://create-react-app.dev/docs/adding-custom-environment-variables/

Environment variables in NodeJs using cPanel

So I'm using cPanel with Setup Node.js App plugin for a Next.js app. (don't asky why cPanel)
Everything is working as expected in development, except for environment variables in production, I set up them manually from the cPanel interface, I restarted/stopped the app, logging the process.env on the server and I don't see the env variables there (not to say when trying to call them they are undefined).
When doing
res.json(JSON.stringify(process.env)); i get a bunch of variables except for the one I manually wrote in cPanel variables interface.
It is important for me to store these variables as secret key because they are API credentials.
Anyone know what I might have misconfigured or had this problem?
Never mind, found the answer, apparenlty was a Next.js misconfiguration. I had to add the following lines of code inside next.config.js in order to read env variables on build version.
require('dotenv').config();
module.exports = {
env: {
EMAIL_NAME: process.env.EMAIL_NAME,
EMAIL_PASSWORD: process.env.EMAIL_PASSWORD,
GETRESPONSE_API_KEY: process.env.GETRESPONSE_API_KEY
}
};
Where EMAIL_NAME, EMAIL_PASSWORD, GETRESPONSE_API_KEY were the variables defined by me on cPanel interface

Change configuration in runtime by changing environment variables using the module node-config

I'm trying to use the node-config module to change some parameters of my configuration (basically logging level) during runtime.
In the official documentation says:
Environment variables can be used to override file configurations. Any environment variable that starts with $CONFIG_ is set into the CONFIG object.
I've checked that this is true when the server starts but it does not seem to work once it's up. (The handler of the watch function is never called when an environment variable is changed unlike a change in the runtime.json file or directly changing a config variable).
I'm currently watching the whole CONFIG object like this:
var CONFIG = require('config');
CONFIG.watch( CONFIG , null , function(object, propertyName, priorValue, newValue){
console.log("Configuration change detected");
});
Does anyone know if this is possible?
The environment is available during startup of a process.
If the process is running, you won't be able to change the environment anymore, the process is in.
The only option is to restart the process or use other mechanisms to communicate with it.
Say for example having a rest or tcp listener inside, where you can transfer your variable inside.
Best regards
Robert
As you must knowing, React is a single page application which is eventually when it is complied is a static page app that means all the files of the react application is complied into vanilla JS and CSS file bundle in a Tarball. Now that Tarball is eventually deployed on a web server. It could be Apache web server, nginx web server or anything which you are using it but an important point is the static app is running in someone else browser and someone access to website CSS and JS are downloaded in a browser and it is running in the browser runtime environment so technically you cannot have a runtime environment variable for someone else browser but may be there would be a way to access them during runtime.
SOLUTION
I have achieved this goal with the package called runtime-cra.
follow the steps on this official documentation: https://blog.risingstack.com/create-react-app-runtime-env-cra/

Resources