I am new to express js. I am working on a project. where i have to send email when the user is updated. but the problem is that once the user is updated. Inside the update success I don't have access to req object or userUpdate. I know its a concept issue. Can you please let me know how to fix this.?
thanks
module.exports.update = function(req, res) {
var body = _.pick(req.body, 'email', 'first_name', 'last_name', 'role', 'clinic_id', 'profile_id');
if (!_.isString(body.email) || !_.isString(body.first_name) || body.email.length == 0 || body.first_name.length == 0) {
res.status(404).send();
} else {
var userUpdate = req.body;
var selector = {
email: userUpdate.email
};
userUpdate.updatedAt = new Date().getTime();
//*********req object and userUpdate have data till this point**************//
db.user.update(userUpdate, { where: selector })
.then(function(result) {
// ****req object and userUpdate are not defined here. WHY??
mailer.sendActivateEmail(result);
// sending response to front end
res.json(result);
}).catch(function(e) {
res.status(500).json(e);
console.log("error updating user:", e);
});
}
};
The problem was in my understanding. I am able to access req object anywhere in the function. The problem occurs in debugging. When i use debugger in my code. I usually don't have access to variables outside of function scope.
When i use console.log to print object before debugger, things work as expected.
Don't have time to actually run your code but I would suggest two things:
Try binding your function call so that the function definitely receives the req object.
db.user.update(userUpdate, { where: selector }).then(updateSuccess.bind(req)))
Define updateSuccess like this
const updateSuccess = (req, result) => { ... }
Try using anonymous functions instead of function, ie.
module.exports.update = (req, res) => {
Could be some weird scoping problem
Related
I'm new to JavaScript and cannot seem to make this work , the topic of quiz depends on the user input... when the user presses next , I get the topic (this also takes user to the main quiz page), then i have to fetch data from the api with the topic as a parameter... I have to process the result of the fetch operation.. Then I have to pass that info to to the main quiz page... but the variable that is supposed to be populated by the fetch request is still undefined when i pass is to the main quiz page
var Allquestions;
var sheetdb = require('sheetdb-node');
// create a config file
var config = {
address: 'https://sheetdb.io/api/v1/9djmf8ydc7hwy',
};
//sheetdb
// Create new client
var client = sheetdb(config);
function downloadquestions(topic) {
console.log(topic);
client.read({ limit: 2, sheet: topic }).then(function(data) {
console.log(data + " in client.read func")
processQuestions(data);
}, function(err){
console.log(err);
});
}
async function processQuestions(data) {
console.log(data + "data in process");
Allquestions = JSON.parse(data);
console.log(Allquestions[0].Question + " This is defined");
}
app.get("/", (req, res) => {
res.render("pages/index", { title: "Home"});
});
// app.post("/" , urlencodedParser ,(req , res) => {
// console.log(req.body.topic);
// })
app.get("/questions", urlencodedParser , (req , res) => {
downloadquestions(req.body.topic);
console.log(Allquestions + " this is undefined");
res.render("/pages/quizpage" , {Allquestions})
})
There are a few issues with your code, you have a broken promise chain, client.read( is a promise, and that promise is going nowhere. You either return it, or await it. To be able to await your will need to also mark your route (req, res) as async too.
Your code is a little mixed up, you have Allquestions as a global var, this isn't great for multi-user, as the last topic is going to override this each time.
Also try and avoid swallowing exceptions in utility functions, try and keep your exception handling at the top level, eg. in your case inside your req/res handler.
So with all this in mind, your refactored code could look something like ->
const sheetdb = require('sheetdb-node');
// create a config file
const config = {
address: 'https://sheetdb.io/api/v1/9djmf8ydc7hwy',
};
//sheetdb
// Create new client
const client = sheetdb(config);
async function downloadquestions(topic) {
const data = await client.read({ limit: 2, sheet: topic });
return processQuestions(data);
}
function processQuestions(data) {
return JSON.parse(data);
}
app.get("/", (req, res) => {
res.render("pages/index", { title: "Home"});
});
app.get("/questions", urlencodedParser , async (req , res) => {
try {
const allQuestions = await downloadquestions(req.body.topic);
res.render("/pages/quizpage" , {Allquestions});
} catch (e) {
console.error(e);
res.end('There was an error');
}
})
I am currently developing a website with an API that I built with node.js, express and MongoDb for the database.
I am curretly learning node and express and cant find my way to create a middleware to verify that the USER ID matches the POSTED BY ID from a COMMENT. That way the USER can only delete his own comments.
My middleware looks like this
verifyUserIdPostedBy.js
const Comment = require('../models/Comment');
var userId
var postedById
module.exports = {
verfyUserIdPostedBy: function (req, res, next) {
userId = req.header('userId')
postedById = Comment.findOne({ _id: req.params.commentId}).populate('postedBy') .exec( function (error, body) {
if (error) throw new Error(error);
req.postedById = body.postedBy._id // assign the ID to the req object
console.log(req.postedById);
});
console.log(userId);
if(userId !== req.postedById)
return res.status(500).json({message: 'Stopped'})
return next();
},
}
My console.log() in the middleware show me exactly the 2 values that I want to compare but I get the error 'Stopped' and my verification never happens. I tried accesing the route with the comment owner and also with not the comment owner and none works
and my route looks like this
comments.js
const express = require('express');
const router = express.Router();
const Comment = require('../models/Comment');
const verify = require('./verifyToken');
const {verfyUserIdPostedBy} = require('./verfyUserIdPostedBy')
// DELETE COMMENT
router.delete('/:commentId', verify, verfyUserIdPostedBy, async (req, res) => {
try {
const removedComment = await Comment.deleteOne({ _id: req.params.commentId });
res.json(removedComment);
} catch(err){
res.json({message:err});
}
})
Like I said I am new at this but cant find a way to do it properly.
Appretiate in advance any help and advice.
Mario
I add comments in your code to explain how it works :
verfyUserIdPostedBy: function (req, res, next) {
userId = req.header('userId')
postedById = Comment.findOne({ _id: req.params.commentId}).populate('postedBy') .exec( function (error, body) {
/* -----this is a callback function------ */
/* the code inside the callback function is executed only when findOne finish and **after** the code outside */
if (error) throw new Error(error);
req.postedById = body.postedBy._id // assign the ID to the req object
console.log(req.postedById);
});
/* this code is executed before the code inside the callback function */
console.log(req.postedById); // undefined, you can check
console.log(userId);
if(userId !== req.postedById) // this is always true
return res.status(500).json({message: 'Stopped'}) // and this line always executes
return next(); // and this line never execute
},
The concept is callback. I strongly advise you to research this keyword, callback is used massively in NodeJS. Nowadays, there are Promise and async/await that allow developers to write asynchronous code in a "synchronous way", but callback is the base.
In order for your code works, 1 simple solution (there are many solutions!) is put comparison code into the callback block, something like :
const Comment = require('../models/Comment');
var userId
var postedById
module.exports = {
verfyUserIdPostedBy: function (req, res, next) {
userId = req.header('userId')
postedById = Comment.findOne({ _id: req.params.commentId}).populate('postedBy') .exec( function (error, body) {
if (error) throw new Error(error);
req.postedById = body.postedBy._id // assign the ID to the req object
console.log(req.postedById);
console.log(userId);
if(userId !== req.postedById)
return res.status(500).json({message: 'Stopped'})
return next();
});
},
}
I am trying to verify if some data is in the session. If not the controller will redirect you to another route, to get that data.
The problem is that I am getting an error "Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client"
I search over StackOverflow and I find that everyone that had this problem fix it using it async/await, but i was already using async await.
Your help will be trully appreciated!
Thank you very much!
Jose
dashboardCtrl.init = async (req, res) => {
//
var frontdata = req.session;
if (!frontdata.user) {
frontdata.user = await userfacebook.findOne({ where: { 'email': frontdata.passport.user } });
};
if (!frontdata.store) {
tmpstoredata = await userstore.findOne({ where: { 'userfacebookId': frontdata.user.id } });
if (!tmpstoredata) {
res.redirect('/toURL');
};
};
};
Note: I am using EJS MATE.
If i do this
dashboardCtrl.init = async (req, res) => {
//
res.redirect('/toURL');
};
Redirect works, the problem is using await. So i dont know how to continue
That error says that you have already sent an answer to the cliente. In other words, you are trying to declare for the second time -> **res.*****.
Check the flow again in case you have twice declared any action on express's "res".
The solution below allows you to have a good structured and readable asynchronous code.
dashboardCtrl.init = (req, res) => {
// I think destructuring looks good
let { user, store } = req.session;
(async () => {
try {
if (!user) user = await userfacebook.findOne({ where: { 'email': frontdata.passport.user } });
let tmpstoredata;
if (!store) tmpstoredata = await userstore.findOne({ where: { 'userfacebookId': frontdata.user.id } });
if (!tmpstoredata) res.redirect('/toURL');
} catch (err) {
// don't forget ;)
}
})()
};
Hope this can help you.
Greetings.
The code was OK
The problem was the EJS MATE
I replace it with EJS
I've been learning to use Angular 6 and NodeJS (with ExpressJS) these past few days. To do this, I decided to create a front-end with Angular 6 (o which theres a form) with the intention of passing information back and forth to my PHPMyAdmin database via the use of an API I created with NodeJS.
As you may have seen from the title, I get the following error when I try to submit my forms information:
"Unhandled rejection TypeError: callback is not a function"
The code I used for the post action was taken from another functioning and similar API, the database receives the question_id and user_id but will not register the questions answers (which is the end goal).
Without furthur ado, here is the code to get and post:
const config = require('../config/config');
const knex = config.db.knex;
const async = require('async');
class TestModel {
getQuestions(callback) {
knex('question')
.select('id', 'libelle')
.orderBy('id', 'asc')
.then((data) => {
callback(data);
});
}
addResponse(reponse, callback) {
knex('reponse')
.insert({
id_user : 1,
id_question : reponse.id,
libelle: reponse.answer,
}).then((data) => {
callback(data);
});
}
}
module.exports = new TestModel();
Here is the rest:
app.post('/quiz', function(req, res, next){
var answers = req.body;
console.log(answers)
for(var i = 0; i<answers.length; i++)
{
var obj = answers[i];
Test.addResponse((obj,result) => {
});
}
res.json({reponseserveur:'True'});
});
Just for reference, "reponse" means response and "libelle" means label.
Thanks in advance for your help!
The correct Syntax is
Test.addResponse(obj, (result) => {
});
it's working:
Test.addResponse((obj,result) => {})
Looks like you're giving your callback as the first parameter (instead of response). It should be 2nd.
You probably wanted to do:
Test.addResponse(res, (obj,result) => {})
Trying to wrap my head around what this error really means, but it's saying Anonymous caller does not have storage.objects.get access to... when I try to get fileData from a bucket file.
app.get('/api/videos', (req, res) => {
const storageBucket = storageClient.bucket(config.video_bucket);
storageBucket.getFiles(function(err, files) {
if (!err) {
let fileArray = [];
files.forEach(function(file) {
const videoAnnotationBucket = storageClient.bucket(config.video_json_bucket);
const videoAnnotationFilename = (file.metadata.name).replace('/', '').replace('.', '') + '.json';
const annotationFile = videoAnnotationBucket.file(videoAnnotationFilename);
// GET ANNONATIONS FOR EACH FILE
annotationFile.get(function(error, fileData) {
if (error) {
console.log('error getting file', error);
}
else {
const remoteJsonUrl = fileData.metadata.mediaLink;
// console.log(fileData.metadata);
request({
url: remoteJsonUrl,
json: true
},
function(jsonReadErr, jsonResp, body) {
console.log('logging body:');
console.log(body);
The error is occuring on the callback, and I'm reading the error via console.log(body) which gives me the error message I stated above.
What's weird is it's saying I'm anonymous when I did gcloud auth login as well as I'm providing creds when I declare storageBucket as such:
const storageClient = storage({
credentials: {
"client_email": "clientEmail",
"private_key": "privateKey",
},
projectId: "projectId"
});
So right off the bar, to avoid any "did you set this" questions, no I am not actually supplying those values I omitted the real values, and we use them elsewhere so I know they are correct.
My question is, what does Anonymous caller mean? And how can I fix it? How is it thinking I am anonymous when I did all the (seemingly) necessary things to use the API?
It's possible that you need to explicitly authenticate within request. This SO thread looks related.
Let us know how explicitly authenticating worked out!