How to call a function dynamically in Node.js [duplicate] - javascript

This question already has answers here:
"Variable" variables in JavaScript
(9 answers)
Closed 1 year ago.
For web browser I can do like this.
function action(){
GLOBAL_VAR = 3
}
let GLOBAL_VAR = 0
let funcName = 'action'
window[funcName]()
console.log(GLOBAL_VAR)
How I can do this for Node.js inside a module?

I'm not sure what your use case is, but doing this practice in a NodeJS environment is even worse practice than using globals in the browser, since atleast with browser specific code the namespace is distinct to the client's machine, but with NodeJS the global variable is stored in the Server memory, accessible to every request potentially.
You might unwittingly create race conditions and a bunch of problems-- maybe even ddoss your own server if you're continually adding data to the global object since it will eat up your heap memory.
You could use global constants, but having routes modify NodeJS globals seems a bit sketch.
If you insist, you would just use the "global" variable name that's accessible anywhere in your NodeJS Express app.
global.globalString = "This can be accessed anywhere!";
More defined example, index.js:
const express = require("express");
const app = express();
const globals = require('./globals');
const PORT = 3000;
//set the global var
global.var = 0;
global.action = function() {
console.log('running action');
return global.var = 3;
}
app.use('/globals', globals);
app.get('/', (req, res) => {
res.send("home route");
})
app.listen(PORT, () => {
console.log("app running on port: ", PORT);
console.log('global var: ', global.var);
})
Then in your routing file,
globals.js:
const express = require('express');
const router = express.Router();
router.get('/', function(req, res){
const action = 'action';
global[action]();
res.send('global route')
});
module.exports = router;
So yeah, just be sure to set the function and initial variable to the global object in your main app file first before you can use them in your routes. I'd still advise against this.

Related

Should you use 'var' or 'let' in the global scope?

Let's say I have this express application and want to add a global variable at the top
import express from 'express';
const app = express();
// var globalScopeVariable = 123;
app.get('/', (req, res) => {
// home page
});
app.get('/create/:message', (req, res) => {
// add block
});
app.get('/add/:peerPort', (req, res) => {
// add peer
});
Would it be good practice to use 'var' or 'let' in this scenario?
In your case (Node.js), neither var nor let make a global scope variable; both will create a module-scope variable (accessible inside this module, but not in other modules). This may be what you want (in which case, let is generally preferred these days, and var should be consigned to history); but it case it isn't, the only way to make a true global scope variable is by direct assignment:
global.globalScopeVariable = 123;
If your variable can be reassigned, then use let otherwise use const. You don't have to bother about var anymore.
You can always consider the following powerful master rules around variable declaration in modern JavaScript.
Stop using var as soon as you can!
Use const whenever you can!
Use let only when you really have to!

How to access global scope variables in callback functions? [JS]

For my user registration I have
const express = require ('express');
const userRouter = express.Router ();
userRouter.get ('/', function getUserList (req, res) {
let User = require ('../models').User;
User.find ({}, function (err, list) {
res.json (list);
});
});
userRouter.post ('/', function createUser (req, res) {
let User = require ('../models').User;
if (req.body.username && req.body.password)
User.create (req.body, function (err, user) {
res.json (user);
});
});
... 3 more functions with the same `let User` ...
module.exports = userRouter;
Here, I have to require the module models twice. I tried setting the User variable as a global variable up at the top of the program, like
const express = ..., userRouter = ...
var User = ...
However this User variable is still not accessible inside my callback functions.
Is requiring the User module multiple times the correct way to do this or am I missing something?
edit: Inside the callback functions, the User variable is undefined.
As #Doug mentioned, you should pass global to the user variable like this:
global.user = ...
This process essentially turns user into a globally accessible variable. You can read more about Node's global here to understand what it does as well as understand what it's implications are too: http://stackabuse.com/using-global-variables-in-node-js/
To #charloetfl ‘s point if it is just within the file, declaring it outside the callback or on top of the file should do. If we are talking about access across all modules and files within the project then adding it to the global object is the way to go about it in node as #doug and #andrewl mentioned.

Node Express Middleware

I am currently writing an express app and want to use some custom middleware that I have written however express keeps throwing an issue.
I have an es6 class that has a method that accepts the correct parameters like below:
foo(req, res, next){
console.log('here');
}
then in my app I am telling express to use it like so:
const module = require('moduleName');
...
app.use(module.foo);
but express keeps throwing this error:
app.use() requires middleware functions
any help would be greatly appreciated.
This error always occurs TypeError: app.use() requires middleware functions
Since you are not exporting that function that's why it's unreachable
try to export it like this from file
exports.foo=function(req, res, next){
console.log('here');
next();
}
You can also use module.exports
module.exports={
foo:function(req,res,next){
next();
}
}
The solution has two parts. First make the middleware function a static method of that class that you export from your module. This function needs to take an instance of your class and will invoke whatever methods you need to.
"use strict";
class Middle {
constructor(message) {
this._message = message;
}
static middleware(middle) {
return function middleHandler(req, res, next) {
// this code is invoked on every request to the app
// start request processing and perhaps stop now.
middle.onStart(req, res);
// let the next middleware process the request
next();
};
}
// instance methods
onStart(req, res) {
console.log("Middleware was given this data on construction ", this._message);
}
}
module.exports = Middle;
Then in your node JS / express app server, after requiring the module, create an instance of your class. Then pass this instance into the middleware function.
var Middle = require('./middle');
var middle = new Middle("Sample data for middle to use");
app.use(Middle.middleware(middle));
Now on every request your middle ware runs with access to the class data.

Express - Passing mysql connection to scripts

I defined mysql connection with all parameters necessary to app.js, how can make visible to other scripts in routes/ by default, without requiring or redefining mysql parameters, just using client.query(..)?
A pattern I use is to set up my db object in a module once and export it: (let's call it utils/mySQL.js)
//I haven't used real mysql in node so excuse the pseudo-syntax:
var db = require('mysql-driver-thingy');
db.connect('localhost', 'sqlport', options...);
db.otherSetupFunctions();
console.log("Finished db setup. You should only see this message once! Cool.");
module.exports = db;
And then I can require the db object everywhere I need it. Since requires are cached, this does't actually call the setup methods multiple times.
In app.js:
var db = require('./utils/mySQL.js');
...
In models/user.js:
var db = require('../utils/mySQL.js');
...
A final option, which isn't recommended, is to pollute the global namespace. This seems to be the answer you're really after:
//set up your db
...
// and now make it available everywhere:
global.client = db.client
You can now magically use the client object in all your modules, without even requiring it.
There are many reasons globals are bad, though:
If your code and other code define globals, they could conflict and overwrite each other.
It's hard to find where you defined the db/client object, etc.
You can inject mysql connection into other scripts like this:
app.js
var mysqlConnection = new Conection(params);
require('controller/main.js)(mysqlConnection);
main.js
module.exports = function(mysqlConnection) {
// You can access your mysql connection here
};
UPDATE:
You can inject several variables same way. Also you still can export methods from module if you need this:
app.js
var mysqlConnection = new Conection(params);
var news = require('model/news.js)(app, mysqlConnection);
news.list(function(err, news) {
// Do something
});
news.js
module.exports = function(app, mysqlConnection) {
var methods = {};
// mysql connection and app available from here
methods.list = function(cb) {
mysqlConnection.list(function(err, data) {
cb(err, data);
});
};
return methods;
};

Variable HTTP/HTTPS Express Server

I'm sure this is just a simple Javascript scoping issue (go figure), but I've tried several different ways and can't seem to get this to work.
The idea is that the Express.js server defaults to HTTP with the call to express.createServer(), but optionally switches to HTTPS upon detection of ./conf/cert.pem and ./conf/key.pem. I'm using asynchronous calls to Node's path.exists(), whereby the second callback argument contains the boolean result.
I have them nested currently so that a HTTPS server isn't created until it's "safe" (we know the outcome of whether the two files exist or not) since no ordering is guaranteed otherwise. However, as I mentioned, I've tried several different ways, but I can't seem to modify the outer app variable.
I'm sure there's a simple fix that I'm not seeing right now, but any help would be appreciated!
app = module.exports = express.createServer();
path.exists('./conf/key.pem', function(exists){
var keyExists = exists;
path.exists('./conf/cert.pem', function(exists) {
var certExists = exists;
if (keyExists && certExists) {
app = express.createServer({
key: fs.readFileSync('./conf/key.pem'),
cert: fs.readFileSync('./conf/cert.pem')
});
}
});
});
This is not ideal. You shouldn't create a regular http server only to have it overwritten by an https server. I think the problem you're referring to comes from the fact that you're setting the app variable below, but not module.exports. So module.exports still refers to the original server created. This is what you should do:
var app = express.createServer({
key: fs.readFileSync('./conf/key.pem'),
cert: fs.readFileSync('./conf/cert.pem')
});
module.exports = app;
There's no reason to check whether the files exist first. If the files don't exist, readFileSync will just throw an ENOENT. There is also no reason to do anything asynchronously before you have even entered the event loop.
I don't know why you would want your server to conditionally be https, but to do something similiar to what you were trying to do there:
var app;
try {
app = express.createServer({
key: fs.readFileSync('./conf/key.pem'),
cert: fs.readFileSync('./conf/cert.pem')
});
} catch(e) {
if (e.code !== 'ENOENT') throw e;
app = express.createServer();
}
module.exports = app;
Or, this might look nicer:
var app;
if (path.existsSync('./conf/key.pem')) {
app = express.createServer({
key: fs.readFileSync('./conf/key.pem'),
cert: fs.readFileSync('./conf/cert.pem')
});
} else {
app = express.createServer();
}
module.exports = app;
Remember, doing things synchronously is fine as long as you don't have to serve a million requests at the same time.

Categories

Resources