NodeJS: Files only update after restarting the express server - node.js

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.

Related

TypeError: Router.use() requires a middleware function but got a Object[using express router] --

The app, I am building with nodeJS expressJS is for connecting to a sqlserver database and retrieving data. Am trying to make the code as modular and
reusable as posssible. So different files for routing and controller. The error I am now facing is-
throw new TypeError('Router.use() requires a middleware function but got a ' + gettype(fn))
^
TypeError: Router.use() requires a middleware function but got a Object
For ease of understanding of the imports, my project structure is as such:
controller
|-- controller.js
db
|-- db.js
query
|-- queries.json
routes
|-- route.js
package.json
server.js
My main server.js file is
const express = require('express')
const bodyParser = require('body-parser')
const cors = require('cors')
const fs = require('fs')
const path = require('path')
const morgan = require('morgan')
const router=require('./routes/route');
const app = express()
app.use(cors());
app.use(bodyParser.urlencoded({ extended: false }));
// parse application/json
app.use(bodyParser.json());
app.use(morgan('dev'));
const port = 3200
app.listen(process.env.PORT || port , (err) => {
if(err)
{
console.log('Unable to start the server!');
}
else
console.log('NodeExpress Data API started running on : ' + port);
})
the controller file is
const express=require('express')
const { sql, poolPromise } = require('../db/db')
const fs = require('fs');
class MainController
{
async getAllData(req, resp)
{
try
{
const pool = await poolPromise
const result = await pool.request()
.query("select * from players");
resp.json(result.recordset)
}
catch (error)
{
resp.status(500)
resp.send(error.message)
}
}
}
const controller=new MainController();
module.exports=controller;
and the route file is
const express = require('express');
const controller = require('../controller/controller')
const router = express.Router();
router.get('/getAllData', controller.getAllData);
So when I insert this line
app.use('api/', router) in the server.js to wire all the modules together and make calls to api endpoint to get all data, I am getting that error mentioned.
What is it about, can anyone explain me in simple terms? Is the error being thrown from the controller file, since I am initializing a new instance of the controller type? Which line from which file is throwing this error? What is the code correction needed to remove this error?
under route.js change to router.get('/getAllData', controller.getAllData()); you have passed controller.getAllData as a handler function instead of controller.getAllData() as per the type of method you have used in class. hope this solves the error.
Try out one of these:
1- if your are using express and doing
const router = express.Router();
make sure to
module.exports = router ;
at the end of your page
2- If your are using express above 2.x, you have to declare app.router like below code. Please try to replace your code
app.use('/', routes);
with
app.use(app.router);
routes.initialize(app);

Store webhooks functions inside a master function

I have set up multiple webhook endpoints that follow the similar structure in Node.js: 1) stringify the JSON request and 2) do something about that stringified request in R.
This consequently leads to a lot of duplicate code, and I attempt to stay DRY by creating a function in which I specify the arguments that actually do change. Here's an example.
First, the top portion of the script:
require("dotenv").config();
const express = require("express");
const app = express();
const port = 3000;
app.use(express.json());
Then, the part I would like to rewrite into a master function (WH) in which everything capitalized below between < and > becomes the argument.
app.post(<ENDPOINT>, foobar);
function foobar(req, res) {
var spawn = require("child_process").spawn;
let body = JSON.stringify(req.body);
var R_shell = spawn("/usr/local/bin/Rscript", [<PATH_TO_SCRIPT>, body]);
res.end("Processing completed");
}
app.get(<ENDPOINT>, (req, res) => res.send(`<html><body><h1>All working!</h1></body></html>
`));
Hence, with two endpoints, I'd end up with:
require("dotenv").config();
const express = require("express");
const app = express();
const port = 3000;
app.use(express.json());
WH(endpoint="foo", script_path="baz")
WH(endpoint="lorem", script_path="dolor")
P.S. Sorry if this is poorly formulated question from a Node.js standpoint—it's my first time developing with Node.js.
If I understood your question correctly, what you can do is something like this:
Firstly, you need to create a function that returns a router with the specified routes (You could create this function in a different file to make the code cleaner).
const {Router} = require('express')
function WH(endpoint, scriptPath) {
const router = Router()
function fn(req, res) {
var spawn = require("child_process").spawn;
let body = JSON.stringify(req.body);
var R_shell = spawn("/usr/local/bin/Rscript", [scriptPath, body]);
res.end("Processing completed");
}
router.post(endpoint, fn);
router.get(endpoint, (req, res) => res.send(`<html><body><h1>All working!</h1></body></html>`));
return router
}
And finally you should use it like this:
require("dotenv").config();
const express = require("express");
const app = express();
const port = 3000;
app.use(express.json());
app.use(WH("/foo", "./baz"))
app.use(WH("/lorem", "./dolor"))

Not getting expected results from included files in Nodejs

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) );

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!

res.download(NodeJS) not triggering a download on the browser

I've been struggling with this for a while and can't seem to find an answer, I'm developing a website with a budgeting option, I'm sending an object from the client to the server, and that server is using PDFKit to create a PDF version of the budget, once it's created I want to actually send back that PDF to the client and trigger a download, this is what I've done
Client-side code:
let data = {
nombre: this.state.name,
email: this.state.email,
telefono: this.state.phone,
carrito: this.props.budget.cart,
subTotal: this.props.budget.subTotal,
IVA: this.props.budget.tax,
total: this.props.budget.subTotal + this.props.budget.tax
}
axios({
method: 'post',
url: 'http://localhost:1337/api/budget',
data: data
})
.then((response) => {
console.log('This is the response', response);
window.open('/download')
})
.catch((error) => {
alert(error);
})
So that data goes to my server-side code perfectly and it looks like this
const pdf = require('pdfkit');
const fs = require('fs');
const path = require('path');
exports.makePDFBudget = (req, res) => {
let myDoc = new pdf;
myDoc.pipe(fs.createWriteStream(`PDFkit/budget.pdf`));
myDoc.font('Times-Roman')
.fontSize(12)
.text(`${req.body.name} ${req.body.phone} ${req.body.email} ${req.body.cart} ${req.body.subTotal} ${req.body.total} ${req.body.tax}`);
myDoc.end()
}
That's creating my PDF, what I want now is that once it's created and the response is sent back to the client, the client opens a new window with the URL "/download" which is set to download that PDF, but that's not happening for some reason, it opens up the new window but the download never starts and it throws absolutely no error I'm my Node console or browser console
this is how I send my file to the client
const fs = require('fs');
const path = require('path');
exports.downloadPDFBudget = (req, res) => {
res.download(__dirname + 'budget.pdf', 'budget.pdf');
}
And this is how my server index looks like
const bodyParser = require('body-parser');
const express = require('express');
const app = express();
const api = express.Router();
const { makePDFBudget } = require('./PDFkit/makePDFBudget.js');
const { downloadPDFBudget } = require('./PDFkit/downloadPDFBudget.js')
app.use(express.static(__dirname + '/../public'));
app.use(bodyParser.urlencoded({extended: true}));
app.use(bodyParser.json({extended: true}));
api.route('/budget')
.post(makePDFBudget)
api.route('/download')
.get(downloadPDFBudget)
app.use('/api', api);
const port = 1337;
app.listen(port);
console.log('Listening on port ', port);
module.exports = app;
I just solved it, the port in which I was running my client obviously was different from the one I was running my server, so I had to open a window to my server's port to trigger the download, I realized this because I threw a console log on the function that was supposed to do the res.download it wasn't showing up. Thanks!
I guess the main problem here:
res.download(__dirname + 'budget.jpg', 'budget.pdf');
Make a correct file name. Your file is pdf, not jpg.
At this code res.end(Buffer.from('budget.pdf')) you sending string, not file content. But headers like you want to send a file.
The last. Your application designed like you will have only one user. Could you add userId to file names? Or use DB for storing data and generate pdf on request without storing a file to the file system.

Resources