dynamically calling functions exported in node - node.js

I'm new to node and gradually learning
I've app.js file which is server and app_functions.js which holds all my app functions
var express = require('express');
var app_functions = require ('./app_functions');
var app = express();
app.get('/', function (req, res) {
res.send('Running NODE!');
});
// Ex: when I request http://ip.address:3000/functionOne
app.get('/:method', function (req, res) {
// I want to call function that "method" holds i.e, in this case 'functionOne'
// and that function will reside in app_functions.js
});
var server = app.listen(3000, function () {
console.log('Server listening');
});
I was able to call those functions using global[] when they are in same file.
My app_functions.js goes like this
exports.functionOne = function functionOne() {
return "functionOne executed";
};
exports.functionTwo = function functionTwo() {
return "functionTwo executed";
};
Please help me. Thanks in advance.

There is no problem with it. Just take property of object and then execute it with (). Example (also here I check that property is function):
var express = require('express');
var app_functions = require('./app_functions');
var app = express();
app.get('/', function(req, res) {
res.send('Running NODE!');
});
// Ex: when I request http://ip.address:3000/functionOne
app.get('/:method', function(req, res) {
// I want to call function that "method" holds i.e, in this case 'functionOne'
// and that function will reside in app_functions.js
if (typeof app_functions[req.params.method] === 'function') {
app_functions[req.params.method]();
}
});
var server = app.listen(3000, function() {
console.log('Server listening');
});

Related

'Sharing' object between NodeJS modules

I'm new to NodeJS development and I'm doing some tests with the socket.io library. Basically, what I want to do is to stablish a socket.io connection between the clients (Angular 6 web app) and the server and broadcast a message when a new user connects.
Right now, the code is quite simple, and this is what I have:
app.js
var express = require('express');
var http = require('http');
var socketIO = require('socket.io');
// Routes
var twitterRoutes = require('./routes/user');
var app = express();
var server = http.Server(app);
var io = socketIO(server); // <== THIS OBJECT IS WHAT I WANT TO USE FROM THE ROUTES
[ ... ]
io.on('connect', (socket) => {
console.log('New user connected');
socket.on('disconnect', (reason) => {
console.log('User disconnected:', reason);
});
socket.on('error', (err) => {
console.log('Error in connection: ', err);
});
});
I want to use the io object inside the user route, but I don't know how to do it:
routes/user.js
var express = require('express');
var config = require('../config/config');
var router = express.Router();
router.post('/login', (req, res, next) => {
// DO ROUTE LOGIC
// I WANT TO BROADCAST THE NEW LOGGED USER USING io.broadcast.emit, BUT DON'T KNOW HOW
// <=====
});
How could I do it? Thanks in advance,
Not sure if it is the best way but you could share things between request handlers using middleware
// define and use a middleware
app.use(function shareIO(req, res, next) {
req.io = io;
next();
})
Then you could use req.io inside request handlers.
router.post('/login', (req, res, next) => {
// DO ROUTE LOGIC
req.io.emit('event')
});
You could do what you want by injecting your IO var in a function
// app.js
var app = express();
var server = http.Server(app);
var io = socketIO(server);
server.use(require('./router')(io))
...
// router.js
module.exports = function makeRouter(io) {
var router = express.Router();
router.post('/login', (req, res, next) => {
// do something with io
}
return router
}
I don't know if it's the best practice, but I've assigned the io object to a property of the global object, and I can access it from everywhere all across the application. So this is what I did:
app.js
var io = socketIO(server);
global.ioObj = io;
routes/user.js
router.post('/login', (req, res, next) => {
// DO ROUTE LOGIC
if (global.ioObj) {
global.ioObj.sockets.clients().emit('new-message', { type: 'message', text: 'New user has logged in' });
}
});

NodeJS, socketIO, multiple files

I'm a little bit confused;
I would like to use socketIO on NodeJS app.
I've created this (pseudo)code:
//server.js
var app = express();
//some code...
var router = require('./app/router');
app.use(router);
var server = app.listen(appConfig.app.port, function () {
var port = server.address().port;
});
var io = require('socket.io')(server);
io.on('connection', function (client) {
console.log('Client connected...');
client.on('join', function (data) {
console.log(data);
});
});
//client.js
var socket = io.connect('http://localhost:5555');
socket.on('connect', function(data) {
socket.emit('join', 'Hello World from client');
});
Everything is fine. But !
At now, I would like to emit event in another file.
I have router and POST request. I want to emit event on POST request (request handler is in another file).
//router.js
router.route("/addmenu").post(function (req, res) {
menuModel.addMenu(req.body,function(data){
//I WANT EMIT HERE
res.json(data)
});
};
);
I have to initialize router before start server, but I have to pass server to IO... How pass IO to router ?
You can try this
//server.js
var app = express();
//some code...
var io;
var getIOInstance = function(){
return io;
};
var router = require('./app/router')(getIOInstance);
app.use(router);
var server = app.listen(appConfig.app.port, function () {
var port = server.address().port;
});
io = require('socket.io')(server);
io.on('connection', function (client) {
console.log('Client connected...');
client.on('join', function (data) {
console.log(data);
});
});
//router.js
module.exports = function(getIOInstance){
router.route("/addmenu").post(function (req, res) {
menuModel.addMenu(req.body,function(data){
//I WANT EMIT HERE
getIOInstance().sockets.emit(...)
res.json(data)
});
};
return router;
);
This solution will work if you want to 'notify' all connected clients.
If you need to notify only a specific client, then I will advise you to use an event-emitter module in order to communicate these events and not share your socket instances across multiple files.
In router.js you can do something like:
//router.js
module.exports = function(io) {
var router = //What you declared it to be
router.route("/addmenu").post(function (req, res) {
menuModel.addMenu(req.body,function(data){
//I WANT EMIT HERE
res.json(data)
});
};
);
return router;
}
//server.js
//Change this line to be like the one below
var router = require('./app/router');
//.........
//.......
//Desired way
var router = require('./app/router')(io);
The answer of #jahnestacado does the job, but in case you already have an existing code base, then you need to change the structure of each file, where you might need the socket.io object, to pass it in as an argument.
A better way to do it then, would be:
To create the getIO() function—just as #jahnestacado did—, where you instantiate the io object (inside server.js), and export it.
var io;
exports.getIO = () => io;
Then require it wherever you need it. But make sure to execute the function only when you need it. Typically inside your controller function:
const getIO = require('../server').getIO;
exports.updateSAE = (req, res) => {
let io = getIO();
io.emit();
// rest of your controller function code
}
Note that I did not call the getIO function outside the controller function. For example, the following would probably not work:
const getIO = require('../server').getIO;
var io = getIO();
exports.updateSAE = (req, res) => {
io.emit();
// rest of your controller function code
}
Simply because the socket.io object could have not been initialized when you call the function, thus returning undefined.

Mocha- Testing Express API With Global Middleware

This is my first express app and I'm having some trouble writing the tests for the endpoints.
At the moment I am not using a database to store the tokens or check for users when logging in.
The tests I have written pass, however they are not complete. How would I test for example a user that has authenticated correctly?
How would I mimmic the authentication process?
Because I've created a global middleware function and checkLoging function how to factor these into my tests?
How do I test the authentication and routs?
This is my code:
'use strict';
var express = require('express');
var session = require('express-session');
var app = express();
var shopifyObj = require('shopify-node');
var shopifyConfig = require("./config/config.json");
var _ = require('underscore');
var shopify = require('./lib/modules/shopify');
var product = require('./lib/modules/product');
var fakeDta = {
user: 'Simba',
};
app.use(session({
secret: 'dsjkfhklaf',
resave: false,
saveUninitialized: true
}));
// Set global middleware function to check for sessions
app.use(function(req, res, next) {
if (req.session && req.session.user) {
// check here for the existence of this user and token in the database.
next();
} else {
next();
}
});
// define middleware function
function checkLogin (req, res, next) {
if (!req.session.user) {
req.session.error = 'Access denied!';
res.redirect('/auth');
} else {
next();
}
};
app.get('/auth', function (req, res) {
var url = shopify.createURL();
res.redirect(url);
});
app.get('/handle-o-auth-response', function (req, res) {
var code = req.query.code;
_.extend(shopifyConfig, {'code': code});
shopify.setAccessCode(code, res, function (err, token) {
if (err) {
res.redirect('/auth');
} else {
_.extend(shopifyConfig, {'access_token': token});
req.session.user = fakeDta.user;
res.redirect('/products');
}
});
});
app.get('/products', checkLogin, function (req, res) {
shopify = new shopifyObj(shopifyConfig);
product.getProducts(shopify, res);
});
var server = app.listen(3000, function () {
var host = server.address().address;
var port = server.address().port;
console.log('App listening at http://%s:%s', host, port);
});
module.exports = server;
These are my tests:
"use strict";
var supertest = require("supertest");
describe("Testing server",function(){
var server;
beforeEach(function () {
/* Node module system caches the evaluated result of each module
to avoid loading and compiling the same javascript file multiple times.
Thus the server instance from app.js is only created once.
*/
delete require.cache[require.resolve('../app.js')];
server = require('../app.js');
});
afterEach(function (done) {
server.close(done);
});
it("should redirect to /auth",function(done){
supertest(server)
.get("/products")
//.expect("Content-type",/json/)
.expect(302, done);
});
it("should redirect to shopify",function(done) {
supertest(server)
.get("/auth")
//.expect("Content-type",/json/)
.expect(302, done);
});
});
What I would do is refactor the code to support mocking or replacing the checkLogin function.
You can do this by exposing the checkLogin function on the exported object from app.js, but that wouldn't be very clean architecturally.
Alternatively you can separate the checkLogin function out to it's own file, and instead of exporting:
module.exports = server;
create a function that takes the checkLogin function that wraps all code that uses the checkLogin function:
var express = require('express');
// skipped require code...
var product = require('./lib/modules/product');
function init(checkLogin) {
var fakeDta = {
user: 'Simba',
};
// skipped code...
// remove the checkLogin function definition!
// skipped code...
return app.listen(3000, function () {
var host = server.address().address;
var port = server.address().port;
console.log('App listening at http://%s:%s', host, port);
});
};
module.exports = init;
Now in your live code you require the file with the checkLogin function, and pass the function into server, and in your testing code you can supply a mock function that will behave exactly as you want in your test, for example returning that the login is valid.
You can either write your own function and pass that one, or use a mocking library such as sinon.
I have json config files each for env: test, dev, prod and config loader that returns config basing on current NODE_ENV:
let ENV = process.env.NODE_ENV;
let env = ENV || 'prod';
module.exports = require('./' + env + '.json');
In authorization middleware:
if(config.env != 'prod' && process.env.DISABLE_AUTORIZATION) return next();
Now I can disable authorization in middleware in test and dev enviroment by setting DISABLE_AUTHORIZATION variable like this:
process.env.DISABLE_AUTORIZATION = true;
PS. To set NODE_ENV I use package cross-env. My scripts:
"scripts": {
"start": "node server.js",
"dev": "cross-env NODE_ENV=dev node server.js",
"test": "mocha --timeout 10000"
},

Why Express.js' app.get() can only work in the same file app.listen() is called?

When app.listen() is in the same file as app.get(), it works; and when I add app.get() calls in other files via require, they don't work:
// ~ means root folder
// This below is in ~/index.js
var routes = require('~/routes/routes.js');
var server = app.listen(3000, function () {
console.log('Listening on port %d', server.address().port);
});
app.get('/snails', function (req, res) {
res.send('ESCARGOT');
});
// This below is in ~/routes/routes.js
var app = module.exports = require('exports')();
app.get('/birds', function () {
res.send('PENGUIN');
});
// SUCCESS -> localhost:3000/snails will return "ESCARGOT"
// FAIL -> localhost:3000/birds will return "Cannot GET /birds"
Second example to prove the point; this time, app.listen() is moved to routes.js:
// ~ means root folder
// The below is in ~/index.js
var routes = require('~/routes/routes.js');
app.get('/snails', function (req, res) {
res.send('ESCARGOT');
});
// The below is in ~/routes/routes.js
var app = module.exports = require('exports')();
app.get('/birds', function () {
res.send('PENGUIN');
});
var server = app.listen(3000, function () {
console.log('Listening on port %d', server.address().port);
});
// FAIL -> localhost:3000/snails will return "Cannot GET /snails"
// SUCCESS -> localhost:3000/birds will return "PENGUIN"
Why is this so? Is it because app.listen() only targets the file that it is called in?
You need to export your app and include it in your routes file
module.exports = app;
And then in your routes file
var app = include('pathtoyourapp.js');
Then you'll have access to your app in your routes file.
You should be doing something along the lines of this in routes/routes.js
module.exports = function(app) {
app.get('/birds', function(req, res, next) {
res.send('Hello');
});
};
and in the index.js
var app = express();
app.get('/snails', function(req, res, next) {
res.send('SNAILS');
});
require('./routes/routes')(app);
app.listen(3000);
should now work.
BTW i'm not 100% sure what you are trying to do by doing require('exports')(), and it looks weird that you are actually exporting that, instead of the app (that contains the new birds route) in routes/routes.js, so that's why it probably doesn't work. Try the way I suggested.
Let me know if you need any additional things.
Use example:
var express = require('express'),
http = require('http'),
port = Number(process.env.PORT || 3000),
app = express();
app.get('/', function(req, res) {
res.end('Test message');
});
http.createServer(app).listen(port);
Most important is:
http.createServer(app).listen(port);
Send app argument for manipulation of servers behaviors.

Pass configuration to controller

I am building a node.js app that will upload files to my S3 bucket using knox. I am able to interact with S3 as expected, but I would like to make my controller to receive configuration so I can dynamically construct my client with configuration values.
My questions is how do I get configuration paramters down the call stack to my controller without being careless?
Disclaimer: I am rather new to Node.js so it could be simply my lack of knowledge in the difference between exports. and module.exports.*
Here is an example of how the interaction works with my code:
app.js
...
config = require('./config/config')['env'];
require('./config/router')(app, config);
...
router.js
module.exports = function(app, config) {
...
var controller = require('../app/controllers/home'); //Is there a way for me to pass config here?
app.post('/upload', controller.upload); //Or here?
...
}
home.js
var knox = require('knox');
var client = knox.createClient({ ... }); //I want to use config.key, config.secret, etc instead of hard-coded values
...
exports.upload = function(req, res) {
//Use client
}
...
Try doing something like this...
var config = require('./config/config')['env'];
// The use function will be called before your
// action, because it is registered first.
app.use(function (req, res, next) {
// Assign the config to the req object
req.config = config;
// Call the next function in the pipeline (your controller actions).
return next();
});
// After app.use you register your controller action
app.post('/upload', controller.upload);
And then in your controller action...
exports.upload = function(req, res) {
//Your config should be here...
console.log(req.config);
}
Ps. I can not try it right now, but I solved a similar issue like this.
You can pass the configuration in as a parameter to you controller
Controller
// controller.js file
module.exports = function(req, res, config) {
console.log('config parameter passed to controller', config);
res.end('config passed')
}
App
// index.js file with the express app
var controller = require('./controller');
var config = {
key1: 'foo'
};
var express = require('express');
var app = express();
var port = 3000;
app.get('/', function(req, res){
controller(req, res, config);
});
app.listen(port);
console.log('app listening on port', 3000);
Demo
You can check out the github repo for a complete example
Alternative approach if you want to call multiple functions from one single route, this will do it.
Route
var users = require('../controllers/users');
app.route('/login').post(function(req, res){
if(users.authenticate()){
console.log('valid user');
if(users.createUser())
{
console.log('user created');
}
}
});
Controller
exports.authenticate = function(req, res, next) {
return true;
};
exports.createUser = function(req, res, next) {
return true;
};

Resources