How to import file globally in node js - node.js

I have created a helper.js file that will contain helper functions. In order to use the helper functions, I have to import the file in all the locations where I want it to be used. Is there any way I can load/import the helper.js file globally?
helper.js
module.exports = {
responseObject: function (status, message, data, error) {
return {
status: status,
message: message,
data: data,
error: error
}
}
}
index.js
// load mongoose
require('./db/mongoose')
const express = require('express')
const app = express()
const port = process.env.PORT || 3000
app.use(helper)
// load routers
const userRouter = require('./routers/user')
app.use(express.json()) // automatically converts incoming requests to json
app.use(userRouter)
app.listen(port)
UserController.js
const User = require("../models/user")
const helper = require("../helper")
exports.createUser = async (req, res) => {
const user = new User(req.body)
try {
await user.save()
res.status(201).send({
status: true,
message: 'Registration success',
data: user,
error: {}
})
} catch (error) {
const response = helper.responseObject(false, "Wrong", {}, error)
res.status(400).send(response);
}
}

From the documentation:
In browsers, the top-level scope is the global scope. This means that
within the browser var something will define a new global variable. In
Node.js this is different. The top-level scope is not the global
scope; var something inside a Node.js module will be local to that
module.
This means you can't just define your responseObject in the "global" scope, as it always refers to the scope local to the module and will not be available to other modules.
But there's a way to do it, although I would not recommend it (search Google or SO why that's the case, this has been discussed in detail already). You can add your function/variable to the global object (which is somewhat similar to the window keyword in browsers):
// in your app.js "add" the exported stuff from the helper-module to the global object
const express = require('express')
...
global.myHelper = require('./helper');
// in e.g. your user-controller you could then access it like
const response = global.myHelper.responseObject(false, "Wrong", {}, error)

Related

require is not define / module.exports is not define with node.js and Express

After receveing help about using Express, I continued to follow tutorials about Node.js. I'm at a point where i'm building my own routes in controllers to create a REST API. I have two files, app.js and /controllers/account-api.js.
Here's my app.js shortened (i deleted the parts that were not used my my test), and the line that is returning me some issues.
import express from 'express';
import exphbs from 'express-handlebars';
import * as accountApiRoutes from './controllers/account-controller.js';
import * as bodyParser from 'body-parser';
var app = express();
app.engine('handlebars', exphbs());
app.set('view engine', 'handlebars');
app.use(bodyParser.urlencoded({extended:true}));
app.use(accountApiRoutes); // ISSUE HERE, i tried ('/account-api', accountApiRoutes) too
app.get('/', function(req, res)
{
res.redirect('/server-home');
});
app.get('/server-home', function(req, res)
{
res.render('server-home');
});
app.listen(1337, '127.0.0.1');
console.log('Express Server running at http://127.0.0.1:1337/');
And here's my ./controllers/account-api.js shortened again to give the main elements that causes the issue :
import express from 'express';
const apiRouter = express.Router(); //ISSUE HERE
var accounts = [];
accounts.push( { code: 1, name: 'Pierrette', adress: 'Sur la Lune'} );
// =========== API ROUTES =========== //
// GET
apiRouter.route('/produit-api/produit/:code')
.get( function(req, res, next) {
var codeSended = req.params.code;
var account = findAccountInArrayByCode(codeSended);
res.send(account);
});
// =========== METHODS AND FUNCTIONS =========== //
// GET
function findAllAccounts() {
return accounts;
}
function findAccountInArrayByCode(codeSended) {
var accountFound = null;
for(i in accounts)
{
if(accounts[i].code === codeSended)
{
accountFound = accounts[i];
break;
}
}
return accountFound;
}
module.exports = { //ISSUE HERE
getApiRouter: function() {
const apiRouteur = express.Router();
return apiRouter;
}
}
The problem is.. This code returns me "module" is not defined.
I use Node.JS with Express and Handlebars.
For what I saw online, when using "app.use", it requires a function. And module.exports too. I tried various solutions, like this one :
account-api.js
const apiRouter = function() { return express.Router() }
...
module.exports = apiRouteur;
The problem is that it changes the type of apiRouteur, when calling apiRouteur.get from IRouter to () => Router, and the routes break.
I don't know how to arrange the code to make the module.exports returning a function that works, or if the problem is not even about the type of value returned, but if I'm missing dependancies, etc...
Thanks for your help.
EDIT : With the explanations I got, I replaced all my ES6 calls to commonjs imports. But it doesn't solve the problem. Now it's "require" that's not define.
I was stuck firstly by "require is not defined", and the solution I was given by reading old SO threads about it, the answer was regularly to use ES6 imports...
ack to the begining I guess ! Maybe I miss something in my project?
Your problem is this line app.use(accountApiRoutes); and you are using a mix of ES6 and commonjs modules.
To fix the module imports (as you are using .js files not .mjs) change all your ES6 imports i.e import * as xyz imports to commonjs imports const x = require('...');
The accountApiRoutes is an object but not a Router object.
To fix you just need to pass the router object to the app.use function.
So you will need to make a couple of changes based on what you have supplied above.
// ./controllers/account-api.js
const express = require('express');
...
module.exports = { //ISSUE HERE
getApiRouter: function() {
return apiRouter; // you have already defined the router you don't need to recreate it
}
}
Properly pass the Router object to the express app.
const express = require('express');
const exphbs = require('express-handlebars');
const bodyParser = require('body-parser');
const accountApiRoutes = require('./controllers/account-controller.js');
...
app.use(accountApiRoutes.getApiRouter());
You could also just set module.exports to your configured router in your account-api.js and then you could pass it directly to app.use as you have already done in your server above. Either way should work. To can do that as follows:
// ./controllers/account-api.js
const express = require('express');
...
module.exports = apiRouter;
And in your server.js
const accountRouter = require('./controllers/account-controller.js');
app.use(accountRouter);

Creating a DB service in an MVC Express app

I am creating a Node / Express / Mongo app and would like to have an MVC-style file layout with a separate database service. I'd like my routes (controllers) to be fairly lean and simply call methods from elsewhere when I need to perform CRUD functions.
This great post had a lot of solid answers. I'll paste below the the answer from EddieDean that seems to be closest to what I'd like to do.
However, when I'm trying to reference the Users object defined in the mongo.js file in my someFile.js file, it comes back as undefined. I am pretty sure I am missing something obvious and would love to know what that is.
I can get a reference to the DB connection itself and call dbConn.Users.addUser(x) but I cannot directly call Users.addUser(x) as in the someFile.js example below.
This seems minor but I've spent too much time on this to not have an answer. Call it a knowledge vendetta.
Thanks.
mongo.js
const { MongoClient } = require('mongodb');
const config = require('./config');
const Users = require('./Users');
const conf = config.get('mongodb');
class MongoBot {
constructor() {
const url = `mongodb://${conf.hosts.join(',')}`;
this.client = new MongoClient(url, conf.opts);
}
async init() {
await this.client.connect();
console.log('connected');
this.db = this.client.db(conf.db);
this.Users = new Users(this.db);
}
}
module.exports = new MongoBot();
Users.js
class User {
constructor(db) {
this.collection = db.collection('users');
}
async addUser(user) {
const newUser = await this.collection.insertOne(user);
return newUser;
}
}
module.exports = User;
app.js
const mongo = require('./mongo');
async function start() {
// other app startup stuff...
await mongo.init();
// other app startup stuff...
}
start();
someFile.js
const { Users } = require('./mongo');
async function someFunction(userInfo) {
const user = await Users.addUser(userInfo);
return user;
}
What I did is simply put all my routes into start function. This isn't the best solution, but as starting point at least not the worst.
So whenever you need an access to DB from some js file, just put them into start, so the mongo could establish the connection first.
So I want get the DB instance in /routes/users file.
const express = require("express");
const mongo = require("./mongo");
const app = express();
const PORT = process.env.PORT || 3000;
(async function start() {
await mongo.init();
app.use("/users", require("./routes/user"));
})();
If someFile.js is required before the mongo.init method is called, the mongoBot instance will have been created, but Users will indeed be undefined. If you need to require someFile before the init method is called, you can move your destructured assignment to inside your someFunction method.

Why is module.exports=router is needed?

In my node.js server conf file, I set app.use('/user', user.js), which maps /user route to a user.js file.
Then I create subrouting in my user.js file to handle my get or post requests.
My question is: what's the responsibility of module.exports=router at the end of this file?
If I remove it, routing stops working, so I don't understand if it is here to tell my server conf file that there are sub paths in user.js?
var express = require('express');
var user = require('../../models/user');
var db = require('../../models/index');
var router = express.Router();
router.get('/addUser',function (req, res, next) {
db.user.create(req.body)
.then(user => res.json({
data: user,
}))
.catch(error => res.json({
error: true,
data: [],
error: error
}));
});
module.exports = router;
When you do
var user = require('../../models/user');
the user object would get whatever is being exported from the module in user.js. So in user.js, the module.exports=router is mapping a router and all logic that's required to map /user (along with the right callbacks etc...)
If you remove it, your require statement can't acquire an exported object from that module, which is why it would fail. Your user object will be nullified effectively.
Check out here for more info: https://www.tutorialsteacher.com/nodejs/nodejs-module-exports
A router cannot listen(PORT) for requests on its own. The router is useful when you have lots of routes. It's useful for separating your app into multiple modules.
const app = express()
app.listen(port)
app is listening for the requests(not the Router) while your user.js is just a separate js file with some codes.
In module.export ,module is a variable that represents the current module and export is an object. Anything you assign to the module.exports will be expose as a module.
copied: Module in Node.js is a simple or complex functionality organized in single or multiple JavaScript files which can be reused throughout the Node.js application.
Once you do module.export = Router Now you have a newly created module. In nodeJs, you need to require a module before use it. const user = require('./user.js') will do that process. Once you require the node module into your app, you need to tell it to execute by app.use('/' , user)
Or you can do something like below too
in your user.js file,
var user = require('../../models/user');
var db = require('../../models/index');
module.export = (app) =>{
app.get('/addUser',function (req, res, next) {
db.user.create(req.body)
.then(user => res.json({
data: user,
}))
.catch(error => res.json({
error: true,
data: [],
error: error
}));
});
}
in your main index.js,
const app = express()
require('./user.js')(app)

Passing options to node module for export functions to use

I am creating a node module and want the end user of this module to be able to pass it configuration options that will have an effect on the modules functions.
For example, with express you can create an express app and pass it to your routes as such:
const express = require('express');
const app = express();
require('./api/routes/login)(app)
and then in your routes file you can use that app -> /api/routes/login
//login.js
module.exports = function(app){
app.get('/login', function(req, res){//blah}
}
So what I am trying to do in my module is something similar in which an end user can pass an optional config parameters for the module's functions to use. This is was I was trying.....
In my module file:
const default_options = {"enabled":true}
module.exports = function(options) {
const options = options || default_options
exports.login = function(credentials) {
if(options.enabled == true){
//do something
}else{
//do something else
}
}
}
And then someone using the module would be able to do something like this:
//some js file
var options = {"enabled":false}
const mod = require('mymodule')(options)
mod.login(creds)
The error I am getting is 'Cannot read property 'login' of undefined'. I suspect it has something to do with me using exports twice but trying to figure out how to structure my module's js file to be able to use these options if passed it and apply them to the exposed functions.
Any help is appreciated, thank you!
You need to return an object from the exported function.
const default_options = {"enabled":true}
module.exports = function(options) {
const options = options || default_options
return {
login: function(credentials) {
...
}
}
}

Dynamically load routes with express.js

I am using express.js as a webserver and would like an easy way to separate all the "app.get" and "app.post" functions to separate files. For example, if I would like to specify get and post functions for a login page, I would like to have a login.js file in a routes folder that is dynamically loaded (will automatically add all of the files without having to specify each one) when I run node app.js
I have tried this this solution!, but it isn't working for me.
app.js
var express=require("express");
var app=express();
var fs=require("fs");
var routePath="./routers/"; //add one folder then put your route files there my router folder name is routers
fs.readdirSync(routePath).forEach(function(file) {
var route=routePath+file;
require(route)(app);
});
app.listen(9123);
I have put below two routers in that folder
route1.js
module.exports=function(app){
app.get('/',function(req,res){
res.send('/ called successfully...');
});
}
route2.js
module.exports=function(app){
app.get('/upload',function(req,res){
res.send('/upload called successfully...');
});
}
Typescript
routes/testroute.ts
import { Router } from 'express';
const router = Router();
router.get('/test',() => {
// Do your stuffs Here
});
export = router;
index.ts
let app = express()
const routePath = path.join(__dirname, 'routes');
fs.readdirSync(routePath).forEach(async (filename) => {
let route = path.join(routePath, filename);
try {
const item = await import(route);
app.use('/api', item.default);
} catch (error) {
console.log(error.message);
}
});
app.listen()
I ended up using a recursive approach to keep the code readable and asynchronous:
// routes
processRoutePath(__dirname + "/routes");
function processRoutePath(route_path) {
fs.readdirSync(route_path).forEach(function(file) {
var filepath = route_path + '/' + file;
fs.stat(filepath, function(err,stat) {
if (stat.isDirectory()) {
processRoutePath(filepath);
} else {
console.info('Loading route: ' + filepath);
require(filepath)(app, passport);
}
});
});
}
This could be made more robust by checking fro correct file extensions etc, but I keep my routes folder clean and did not want the added complexity
With this approach, there is no need to write routes manually. Just setup a directory structure like the URL paths. Example route is at /routes/user/table/table.get.js and API route will be /user/table.
import app from './app'
import fs from 'fs-readdir-recursive'
import each from 'lodash/each'
import nth from 'lodash/nth'
import join from 'lodash/join'
import initial from 'lodash/initial'
const routes = fs(`${__dirname}/routes`)
each(routes, route => {
let paths = route.split('/')
// An entity has several HTTP verbs
let entity = `/api/${join(initial(paths), '/')}`
// The action contains a HTTP verb
let action = nth(paths, -1)
// Remove the last element to correctly apply action
paths.pop()
action = `./routes/${join(paths, '/')}/${action.slice(0, -3)}`
app.use(entity, require(action))
})
Example route:
import { Router } from 'express'
import Table from '#models/table.model'
const routes = Router()
routes.get('/', (req, res, next) => {
Table
.find({user: userIdentifier})
.select('-user')
.lean()
.then(table => res.json(table))
.catch(error => next(error))
})
module.exports = routes

Resources