Writing json back but assigned as a variable - node.js

I have the following node code which successfully writes as a json object:
const writeFile = (fileData, callback, filePath = dataPath, encoding = 'utf8') => {
fs.writeFile(filePath, fileData, encoding, (err) => {
if (err) {
throw err;
}
callback();
});
};
/* adds a new customer to the list */
router.post('/', async (req, res, next) =>
{
readFile(data => {
// add the new user
data = req.body;
writeFile(JSON.stringify(data, null, 2), () => {
res.status(200).send('whole content updated');
});
},
true);
});
This works fine if I want to write back as properly formatted json, ie
{"example": "hello"}.
However due to various reasons I want to write the following back:
var systemCode = {"example": "hello"}
How would I go about changing the node code to reflect this? Just to clarify, I'm writing this back as a physical .js file.

You can build the string you wish to write in the post handler, then write this to the file.
For example:
/* adds a new customer to the list */
router.post('/user', async (req, res, next) =>
{
readFile(data => {
// add the new user
data = req.body;
const fileContents = "var systemCode = " + JSON.stringify(data, null, 2);
writeFile(fileContents, () => {
res.status(200).send('whole content updated');
});
}, true);
});

Related

How to make express download link with GridFsBucket?

As the title says, how do you make a direct download link with a file from mongoDB(GridFsBucket) using express?
The file should be downloadable from memory, as i dont want to save it temporarily on the server.
I have this method:
async function downloadFileFromDB(fileId) {
var gridfsbucket = new mongoose.mongo.GridFSBucket(mongoose.connection.db, {
chunkSizeBytes: 1024,
bucketName: 'filesBucket'
});
try {
const stream = gridfsbucket.openDownloadStream(fileId)
const fileBuffer = Buffer.from(stream)
return fileBuffer
} catch (err) {
stream.on('error', () => {
console.log("Some error occurred in download:" + error);
})
console.log(err);
}
}
And this route:
router.get('/download-file', async (req,res) => {
const fileId = req.query.fileId
const ObjectFileId = new ObjectId(fileId)
const fileBuffer = await fileFacade.downloadFileFromDB(ObjectFileId)
res.download(fileBuffer)
})
But res.download wants a path and not a buffer. Aswell im not sure i can make a buffer directly from the openDownloadStream method.
Can anyone help?
I believe you need to write the data to your res object. I accomplished this like:
const readStream = gridfs.openDownloadStreamByName(filename);
readStream.on("data", (chunk) => {
res.write(chunk);
});
readStream.on("end", () => {
res.status(200).end();
mongoClient.close();
});
readStream.on("error", (err) => {
console.log(err);
res.status(500).send(err);
});
So, you may just have to do:
res.write(fileBuffer).end();
//// Instead of doing:
// res.download(fileBuffer);

Express returns 404 even though the route exists

This is my router module:
router.post("/", function (req, res, next) {
var url = req.body.url;
youtubedl.getInfo(url, function (err, info) {
// handle errors here
if (err) {
console.log(err);
res.status(500).send("youtube-dl error");
} else {
var fields = info.title.split('-');
var artist = sanitizeArtistOrTitle(fields[0].trim());
// TODO: handle possibility of - in artist/song name
var title = sanitizeArtistOrTitle(fields[1].trim());
const options = {
apiKey: geniusKey,
title: title,
artist: artist,
optimizeQuery: true
};
geniusSong(options)
.then(function (result) {
urlFields = result.url.split('/');
// check if the name of the song and artist are in the url
// since the api seems to return a random lyric page
// when the actual page cannot be found
var titleAndArtist = urlFields[3].split('-').join(' ').toLowerCase();
if (titleAndArtist.includes(artist.toLowerCase()) &&
titleAndArtist.includes(title.toLowerCase())) {
// get the lyrics and write to a file
req.options = options;
next();
} else {
res.status(500).send("genius API error on retrieving lyrics");
}
}).catch(function (err) {
console.log(err);
res.status(500).send("genius API unknown error");
})
}
})
}, function (req, res) {
console.log(__dirname);
geniusLyrics(req.options)
.then(lyrics => sanitizeLyrics(lyrics))
.then(sanitizedLyrics => fsPromise.writeFile("./aux_files/words.txt",
sanitizedLyrics.toString()))
.then(console.log("written to file"))
.then(res.status(200).sendFile(path.join(__dirname, "../aux_files", "words.txt"),
{headers: {'Content-Type': 'text/plain'}}))
.catch(function (err) {
console.log(err);
res.status(500).send("Could not write lyrics to file");
});
})
function sanitizeLyrics(lyrics) {
var regexp = /\[[\w ]*\]/g;
return lyrics.replace(regexp, '');
}
// remove unncessary parts of the video title e.g. "feat. ...",
// "[Official Music Video]"
function sanitizeArtistOrTitle(value) {
var regexp = /(ft\..*$|\(.*$|\[.*$|feat\..*$)/
return value.replace(regexp, '');
}
module.exports = router
And in app.js I have:
var lyrics = require('./routes/lyrics');
app.use('/api/lyrics', lyrics);
What I don't understand is that the route returns a 404 when it's called by my frontend:
POST /api/lyrics 404 4400.863 ms - 351
I can see in my filesystem that the file has been written, so I know that the middleware executed successfully, but I'm not sure where the error is coming from. If I try to fetch from the route again (after the file has been created), there is no error and everything works properly.

How can I get list record from SQL Server in NodeJS

I start to develop a simple web application with NodeJS. and when I try to get a list record from SQL Server to show on the list page but somehow it's not working.
Here is the code :
const express = require("express");
const bodyParser = require("body-parser");
const sql = require("mssql");
const DBUtils = require("./DBUtils");
const app = express();
app.get("/all", (req, res, next) => {
let mypromise = new Promise((reso, rej) => {
let nameList = DBUtils.getNameList(sql);
if (nameList !== null || typeof nameList !== "undefined") {
reso(nameList);
} else {
rej("Error");
}
})
.then((result) => {
res.send(result);
})
.catch((err) => {
console.log(err);
});
});
app.get("/", (req, res, next) => {
console.log("the / route");
res.send("<h1>Hello to NodeJS</h1>");
});
app.listen(5003);
My DBUtils
const config = {
user: "sa",
password: "123",
server: "DESKTOP-7KGJI7L", // You can use 'localhost\\instance' to connect to named instance
database: "java",
options: {
encrypt: false,
},
};
const getNameList = (sql) => {
let nameList = "";
let errorString = "";
// Create connection
sql.connect(config, function (err) {
// Err
if (err) {
console.log(err);
}
// Create Request object
let sqlRequest = new sql.Request();
// QueryString
let queryString = `select * from NAME`;
// Run the query
sqlRequest.query(queryString, (err, data) => {
if (err) console.log(err);
//console.log(data); //data.recordset(array)[index].name
data.recordset.forEach((el) => {
nameList += `<li>${el.name}</li>`;
});
return nameList;
});
});
};
exports.getNameList = getNameList;
I pretty sure something wrong in Promise line but don't know how to fix it. Any suggest?
I think you are a newbie in Nodejs You made a common mistake. You did not use promise pattern correctly. Also, no need to pass next callback unless required.
Change getNameList as below :
const getNameList = (sql) => {
let nameList = "";
let errorString = "";
// Create connection
return new Promise (function(resolve,reject) {
sql.connect(config, function (err) {
// Err
if (err) {
console.log(err);
reject(err)
}
// Create Request object
let sqlRequest = new sql.Request();
// QueryString
let queryString = `select * from NAME`;
// Run the query
sqlRequest.query(queryString, (err, data) => {
if (err) {console.log(err)
reject(err)
}
//console.log(data); //data.recordset(array)[index].name
data.recordset.forEach((el) => {
nameList += `<li>${el.name}</li>`;
});
resolve(nameList);
});
});
})
};
Change app.get("/all") as below:
app.get("/all", (req, res) => {
DBUtils.getNameList(sql).then(function(list) {
res.status(200).send(list)
}).catch(function(err) { //handle error here
res.status(500)
})
})
Moreover, learn how to use promises and async-await.
Use appropriate body-parser as per requirement ie json, text etc.
Learn how and when to use next

return value not getting logged from module exports

I'm writing a code that uses a library(jsforce) to query on Salesforce and get the records.
Currently, to keep the code clean, I'm separating the index and rest calls file. Here is my code.
var jsforce = require('jsforce');
const uName = 'myId';
const pwd = 'myPwd';
const servKey = 'myKey';
var conn = new jsforce.Connection();
var login = conn.login(uName, pwd, servKey, function (err, res) {
if (err) { return false; }
return true;
});
module.exports = {
myCases: () => {
console.log(`I'm called`);
login.then(() => conn.query(`Select ID, Subject from Case where status='new'`, function (err, openCases) {
if (err) { return console.error(err); }
return openCases;
}));
}
}
and my index file is as below.
const restServices = require('./restServices');
var test = function () {
restServices.myCases((err, data, response) => {
console.log('err')
console.log(err)
console.log('data');
console.log(data);
console.log('response');
console.log(response);
});
}
test();
When I run it, my log prints only I'm called (from restServices.js). but none of the data from my index.js is printed.
also when I add a console.log(openCases), it prints exactly the required data.
please let me know on where am I going wrong in returning the data and how can I fix this.
Thanks
To mycase pass an callback
Example in service.js
Mycase(callback) =>{
// response, err from db then
Callback(err, response)
}
In index.js
Service.mycase((err, response) =>{
Console.log (err, response)
}

Assign value to variable outside mongo query in nodejs

Right now i have this code
router.get('/export', function(req, res, next) {
var postData, eventData, messageData, userData
Posts.list().then(data=> {
var jsonOutput=JSON.stringify(data)
postData=jsonOutput //this doesnt work
})
.catch(erro => res.status(500).send('error'))
Events.list().then(data=> {
var jsonOutput=JSON.stringify(data)
eventData=jsonOutput //this doesnt work
})
.catch(erro => res.status(500).send('error'))
Messages.list().then(data=> {
var jsonOutput=JSON.stringify(data)
messageData=jsonOutput //this doesnt work
})
.catch(erro => res.status(500).send('error'))
Users.list().then(data=> {
var jsonOutput=JSON.stringify(data)
userData=jsonOutput //this doesnt work
})
.catch(erro => res.status(500).send('error'))
//Then when all data from colections is retrieve i want to use the 4 variables that i created in the beggining
});
So basicly im trying to retrieve the data from my mongo database and then assign the results to that 4 variables that i create, but im not getting success.
For what i´ve been seeing i have to use async but im having some trouble doing it.
I don't like too much mrlanlee solution. This is a typical situation where using async / await can really make sense. Anyway, the Hugo's solution (the second one, with async await), even if it just works, will make the four queries in sequence, one after another to. If you want a clean, working and parallel solution, check this:
router.get('/export', async function(req, res, next) {
let data
try {
data = await Promise.all([
Posts.list(),
Events.list(),
Messages.list(),
Users.list()
]);
// at this point, data is an array. data[0] = Posts.list result, data[1] = Events.list result etc..
res.status(200).json(data)
} catch (e) {
res.status(500).send('error');
}
});
The other answer from Sashi is on the right track but you will probably run into errors. Since your catch statement on each promise returns 500, if multiple errors are caught during the query, Express will not send an error or 500 each time, instead it will throw an error trying to.
See below.
router.get('/export', function(req, res, next) {
var postData, eventData, messageData, userData
try {
postData = Posts.list().then(data=> {
return JSON.stringify(data);
});
eventData = Events.list().then(data=> {
return JSON.stringify(data)
});
messageData = Messages.list().then(data=> {
return JSON.stringify(data);
})
userData = Users.list().then(data=> {
return JSON.stringify(data)
});
} catch (err) {
// this should catch your errors on all 4 promises above
return res.status(500).send('error')
}
// this part is optional, i wasn't sure if you were planning
// on returning all the data back in an object
const response = {
postData,
eventData,
messageData,
userData,
};
return res.status(200).send({ response })
});
For explanation of why you weren't able to mutate the variables, see Sashi's answer as he explains it.
The variables defined outside the async code is out of scope of the async functions. Hence you cannot store the returned value from the async functions in those variables.
This should work.
router.get('/export', function(req, res, next) {
var postData, eventData, messageData, userData
postData = Posts.list().then(data=> {
var jsonOutput=JSON.stringify(data);
return jsonOutput;
}).catch(erro => res.status(500).send('error'));
eventData = Events.list().then(data=> {
var jsonOutput=JSON.stringify(data);
return jsonOutput;
}).catch(erro => res.status(500).send('error'));
messageData = Messages.list().then(data=> {
var jsonOutput=JSON.stringify(data);
return jsonOutput;
}).catch(erro => res.status(500).send('error'));
userData = Users.list().then(data=> {
var jsonOutput=JSON.stringify(data);
return jsonOutput;
}).catch(erro => res.status(500).send('error'));
});
Using Async/Await is a much neater solution.
router.get('/export', async function(req, res, next) {
var postData, eventData, messageData, userData;
try{
postData = await Posts.list();
eventData = await Events.list();
messageData = await Messages.list()
userData = await Users.list();
catch (e){
res.status(500).send('error');
}
});

Resources