Not getting expected results from included files in Nodejs - node.js

I'm not getting expected results by including files in Nodejs. Here is my code:
Service Route File
const express = require('express');
const router = express.Router();
const path = require('path');
const config = require('../config');
const serviceAdapter = require('./serviceAdapter');
module.exports = (preRequestPath, serviceBaseUrl) => {
console.log("On server start", preRequestPath)
router.post('/*', (req, res) => {
console.log("On request", preRequestPath)
const axiosHttp = serviceAdapter(serviceBaseUrl);
axiosHttp.post(preRequestPath+req.path, req.body).then(resp => {
res.send(resp.data)
}).catch(err => {
res.status(404).sendFile(path.join(__dirname + '/../404.html'));
});
});
return router;
}
Main Server File
const express = require('express');
const userApiService = require('./routes/userService');
const userAdminService = require('./routes/userService');
app.use('/api/user_service/', userApiService("/api", config.userServiceUrl) );
app.use('/admin/user_service/', userAdminService("/admin", config.userServiceUrl) );
var server = app.listen(3000, function(){
console.log('Server listening on port 3000');
});
module.exports = server;
Expecting Console Result:
On server start /api
On server start /admin
On request /api (when hitting http://baseurl.com/api/<anything>)
On request /admin (when hitting http://baseurl.com/admin/<anything>)
But Getting Console Output as:
On server start /api
On server start /admin
On request /api (when hitting http://baseurl.com/api/<anything>)
On request /api (when hitting http://baseurl.com/admin/<anything>)
Both the time, returning /api path.
Can anyone tell me why is it happening and what's the solution?

You're creating only one router in userService.js (the first file). It's created once before the function so you really only end up with one router. The first time you require it the router gets created, but the second time you require it Node knows it was already loaded and it's not re-initialized. You should be creating a different router for each case like this:
const express = require('express');
// const router = express.Router(); <-- don't do it here
const path = require('path');
const config = require('../config');
const serviceAdapter = require('./serviceAdapter');
module.exports = (preRequestPath, serviceBaseUrl) => {
const router = express.Router(); // <--- create a new router for each case
console.log("On server start", preRequestPath)
router.post('/*', (req, res) => {
console.log("On request", preRequestPath)
const axiosHttp = serviceAdapter(serviceBaseUrl);
axiosHttp.post(preRequestPath+req.path, req.body).then(resp => {
res.send(resp.data)
}).catch(err => {
res.status(404).sendFile(path.join(__dirname + '/../404.html'));
});
});
return router;
}
Also in your main server file you only need to require it once. It's just a function to create the service so you don't need 2 different variables holding that function. So you can initialize both using the one function like this:
// const userApiService = require('./routes/userService');
// const userAdminService = require('./routes/userService');
const service = require('./routes/userService');
app.use('/api/user_service/', service("/api", config.userServiceUrl) );
app.use('/admin/user_service/', service("/admin", config.userServiceUrl) );

Related

Cannot post request to nodejs route on ECS but can locally (404 error)

I’ve been having an issue with deploying my nodejs App on AWS ECS Fargate. Running the app locally on my device with nodemon or building the app and running the build file is successful and I can ping my routes using postman. The issue happens when I deploy this same exact code on AWS; using postman, to do a POST request, I get a 404 error. Please note, I'm running a Node:14 container.
For reference, my nodejs code is structured in a way where there’s a main route.js file containing all routes, then there are specific route files, for example listingRoute.js, contains all the sub-routes then there are controllers (.js files) containing all the logic where I export the function and tie it with the route in the listingRoute.js example.
Here's what my main Route.js file looks like:
const express = require('express');
const error = require('../Middleware/error');
const listingRoute = require('../Routes/listingRoute');
module.exports = function (app) {
//Middleware
app.use(express.json());
app.use(express.urlencoded({ extended: false , limit : '20mb' }));
app.use('/listing', listingRoute);
//The final middleware to be called in case of an unhandled error.
app.use(error);
process.on('uncaughtException', function(err) {
// Handle the error safely
console.log(err)
})
};
My listingRoute file
const express = require("express");
const route = express.Router();
const listingController = require("../Controllers/listingController");
require('dotenv').config();
route.post("/create", listingController.createListing)
route.post("/update", listingController.updateListing)
route.post("/read", listingController.getListing)
route.post("/delete", listingController.deleteListing)
...
...
...
...
...
route.post("/getMostPopular" , listingController.getMostPopular)
route.post("/getByCategory" , listingController.getByCategory)
route.post("/getAllTOS" , TOSController.getTOSByListing)
route.post("/getTOS" , TOSController.getTOSByID)
route.post("/updateTOS" , TOSController.updateTOS)
route.post("/deleteTOS" , TOSController.deleteTOS)
route.post("/createTOS" , TOSController.createTOS)
route.post("/getListingsByIDs" , listingController.getListingsByIDs)
route.post("/cacheImagesNewCDN" , listingController.cacheImagesNewCDN)
module.exports = route;
My listingController file
const listingModel = require('../Models/listingModel');
const moment = require('moment')
const axios = require('axios');
var fs = require('fs');
const createCsvWriter = require('csv-writer').createObjectCsvWriter;
var fs = require('fs');
//tested
const createListing =async (req, res) => {
try {
//some logic here
}
catch (err) {
console.log(err)
return res.status(500).json({ error: err.message });
}
}
const updateListing = async (req, res) => {
try {
//some logic here
}
catch (err) {
return res.status(500).json({ error: err.message });
}
}
module.exports = {
getListing,
updateListing,
deleteListing,
createListing,
listingwithViews,
advertisedListings,
filterListings,
pressedOnBookNow,
cacheImages,
recommendListings,
getCacheMetaData,
addIndoorAmenity,
missingFromFilter,
adjustCreativeStudios,
listingsToCSV,
getAllListing,
getDiscountedListings,
addRevenueToListings,
getMostPopular,
getByCategory,
getListingsByIDs,
cacheImagesNewCDN,
getOwnersPhones
}
All the routes starting from getMostPopular till the end of the list give an error 404 not found although I have done the same procedure to all of them. Any ideas why this is happening? If you feel this isn't enough information to help diagnose, let me know and i'd be happy to provide more details. You're help would be beyond appreciated, thanks!

NodeJS: Files only update after restarting the express server

I am using nodejs with express for a small backend application which just returns a json file from another directory.
Example scenario:
My json files are in the directory "/var/data", so e.g. "/var/data/hello.json". If I start the nodejs backend with "node index.js" everything works as expected.
But if I change the contents of a json file, I still get the old version from the backend.
How can I set this up, so that my backend nodejs server detects these file changes in another directory without restarting it?
index.js:
const express = require('express');
const fs = require('fs');
const app = express();
app.use(express.json());
const myDataPath = "/var/data/";
app.get("/:id", (request, response) => {
let id = request.params.id;
let path = myDataPath + id + ".json";
if (fs.existsSync(path)) {
response.json(require(path));
} else {
response.sendStatus(404);
}
});
Issue is likely with using "require", this is a guess, but maybe require doesn't run twice for optimization reasons.
const express = require('express');
const fs = require('fs');
const app = express();
app.use(express.json());
const myDataPath = './var/data/';
app.get('/:id', (request, response) => {
let id = request.params.id;
let path = myDataPath + id + '.json';
console.log(path);
if (fs.existsSync(path)) {
response.json(JSON.parse(fs.readFileSync(path)));
} else {
response.sendStatus(404);
}
});
app.listen(1025);
The above code snippet worked on my testing example, I used readFileSync to retrieve the data, uncached, and the response changes when the file is modified, without needing to restart the app.

Node.JS Application - Tasks and API

General question.
I am looking to create a console-like application with Node.js that also has api capabilities. It will have timed task that will run on a schedule but also be available to send http request to. My problem is that while I've created the api. I don't know how to go about creating basic task to be performed on a schedule while the server stays running in case http request is made for different types of task.
Main idea is to have the task schedule to run while also keeping the server running and waiting for http request
Folder paths
folders
-controllers
-models
-modules
-node-modules
-routes
general files
app.js
package-lock.json
package.json
server.js
task.js
Proposed area for Scheduled task to be performed:
index.js
const { checkTablesForData, requestRoutine, runNecessaryUpdate } = require('./task')
function Main() {
...
\\task to be executed
\\Check the table for records to be processed
let obj = checkTablesForData();
\\Send third party request with object data. ie - id's
obj.map( id => {
\\call request routine
requestRoutine(id)
})
\\Run final process
runNecessaryUpdate(id)
}
task.js
checkTablesForData(){
...
}
requestRoutine(id){
...
}
runNecessaryUpdate(id){
...
}
module.exports = { runNecessaryUpdate, checkTablesForData, requestRoutine }
Code for api setup
app.js
const express = require('express')
const path = require('path')
const app = express() //, api = express();
const cors = require('cors');
const bodyParser = require('body-parser');
app.get('/', function(req, res){
res.redirect('./api')
})
const api = require('./routes/api');
app.use('/api', api)
module.exports = app
server.js
const app = require('./app');
const port = process.env.PORT || 3000;
app.listen(port, 'localhost', () => {
console.log(`Server is running on port ${port}`);
});
api.js
const express = require('express');
const router = express.Router();
//Controller Modules
const controller = require('../controllers/homeController');
//Routes
router.get('/request/:id', controller.post)
module.exports = router;
controller.js
//Send request to 3rd party api
export.post = function(req, res){
const options = {
....
}
return request(options)
.then( response => {
...
}
.catch( error => {
\\error routine
}
}
Advice is very much needed.
Thanks!

Using an ExpressJS router with subdomains

Due to my shared-hosting situation, I was forced to have all incoming requests redirected to a non-80 port on localhost, which I did through htaccess. This mutates the HTTP host header to always say localhost, no matter what subdomain I try to request. Simple enough, I found a workaround to use x-forwarded-host instead, but this means that I'm not able to rely on any of the Express subdomain middleware packages currently available on NPM, as they all rely on that host header (as far as I'm aware).
So I managed to send requests to the router. But for some reason, any request handling I try to do with the router for the specific subdomain that I have activated, won't get picked up by the router, and passes straight on through to the 404 handler.
/index.js:
const path = require('path');
const fs = require('fs');
const express = require('express');
const app = express();
const PORT = 30001;
const subdomainHosts = [];
fs.readdirSync('./routes/subdomain').filter(file => file.endsWith('.js')).forEach(host => {
subdomainHosts.push(host.split('.js')[0]);
});
const forwardSubdomain = require('./middlewares/forwardSubdomain');
app.use(forwardSubdomain(subdomainHosts));
app.use(express.static(path.join(__dirname, 'public')));
app.use((req, res, next) => {
return res.status(404).sendFile(path.join(process.cwd(), 'public/404.html'));
});
/middlewares/forwardSubdomain.js:
module.exports = (subdomainHosts) => {
return (req, res, next) => {
let host = req.headers['x-forwarded-host'] ? req.headers['x-forwarded-host'] : '';
host = host.split(':')[0].split('.example.com')[0];
const isSubdomain = (host && subdomainHosts.includes(host));
if (isSubdomain) {
const subdomainRouter = require(`../routes/subdomain/${host}.js`);
return subdomainRouter(req, res, next);
}
next();
};
};
/routes/subdomain/test.js:
const path = require('path');
const express = require('express');
const router = express.Router();
router.use(express.static(path.join(process.cwd(), 'test')));
module.exports = router;
/test/ contains a simple hello world index.html. Yet, trying to access test.example.com gives me the 404.
I'm pretty certain that I'm missing something obvious, but I've been sitting on this for a bit too long, hence the cry for help.

how to add custom function to express module

I am trying to add a method
loadSiteSettings to express module
In app.js
var express = require('express');
var path = require('path');
var mongoose = require('mongoose');
//Set up default monggose connection for mongo db
var mongoDB = 'mongodb+srv://***:*****#cluste******j.mongodb.net/cms?retryWrites=true&w=majority';
mongoose.connect(mongoDB,{useNewUrlParser: true});
//Get the default connection
var db = mongoose.connection;
//Bind connection to error event (to get notification of connection errors)
db.on('error',console.error.bind(console, 'MongoDB connection error:'));///????????
var app = express();
///////////////////////////////////////////////////////////
var indexRouter = require('./routes/index');
app.loadSiteSettings = async function()
{
let setting = await db.collection('settings').findOne();
app.locals.siteSettings = setting;
}
app.loadSiteSettings();
//////////////////////////////////////////////////////
module.exports = app;
Index.Js for router
var express = require('express');
var router = express.Router();
var app = require('../app');
var util = require('util');
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index');
});
///////////////////////////////////////////
router.get('/reloadSettings', function(req,res,next){
app.loadSiteSettings();
})
///////////////////////////////////////
module.exports = router;
so problem lies here, when server start it calls app.loadSiteSettings() in app.js
but when i use route '/reloadSettings' it seems app is undefined in index.js
This is an issue with circular dependencies and module.exports. This answer shows the same problem.
What's happening is app.js is required first and starts processing. The important thing to understand is that a file pauses execution while requiring a new file.
So when app.js requires ./routes/index, it has not finished processing, and has not reached module.exports = app. This means that when your routes file requires app.js, it's requiring it in its current state, which is the default export {}.
Thankfully there's a very simple fix:
// can be imported and tested separately from the app
const loadSiteSettings = function() {
return db.collection('settings').findOne();
}
router.get('/reloadSettings', async function(req,res,next){
let settings = await loadSiteSettings();
req.app.locals.siteSettings = settings
res.send(200); // signal the response is successful
})
This explains the issue in a lot more depth in case you're interested

Resources