What's the way of error handling in my case ? - node.js

I'm trying to make my Server side part to handle the errors from my 'Controllers' class to my 'Routes' class so i can show them in the Postman.
I think i should work with Promises but i don't get the way they works.
This is the code in my Controller Class,
async validatingWithDB(email: string, password: string) {
await this.client.connect(async () => {
try {
let saltKey = await this.client.query(
"SELECT salt FROM userinfo WHERE email=$1", [email]);
if (saltKey.rowCount == 1) {
let hashedLoginPassword = this.saltingValidation(password, saltKey.rows[0].salt).hash;
let result = await this.client.query(
'SELECT id FROM userinfo WHERE email=$1 AND password=$2', [email, hashedLoginPassword]);
if (result.rowCount > 1 || result.rowCount < 1) {
throw Error("Wrong or non existing user !");
} else {
console.log("Succes Login !");
}
} else {
throw Error("Wrong or non existing user !");
}
} catch (err) {
console.error(err.message);
}
});
};
}
//this is in Routes Class
app.route('/login')
.post(async (req: Request, res: Response) => {
try {
if (req.body.email !== 0) {
if (req.body.password !== 0) {
await
this.authenticationService.validatingWithDB(req.body.email,
req.body.password)
res.status(200).send(new Result(
true, { Message: 'Login Successfully !'
}
));
} else {
throw new Error("Password too short");
}
} else {
throw new Error("Email is too short");
}
} catch {
res.status(400).send(new Result(
false, { Message: 'Bad request, Please try again' }, ErrorCodes.BadRequest
));
}
})

Related

Non-admin User checkout (Create Order) -- Product is not defined

I am a webdev student trying to create an Ecommerce -API with Node and Express JS connected with MongoDB but I am getting this return in postman : "Product is not defined" in my Non_Admin Checkout function.
I don't really know what my mistakes are. Can you help me?
Here are my codes:
UserController
module.exports.checkout = async (data) => {
try{
let is_user_updated = await User.findById(data.userId).then((user) => {
user.orders.push({productId: data.productId})
return user.save().then((updated_user, error) => {
if(error){
return false
}
return true
})
})
}catch(err){return err.message}
try{
let is_product_updated = await Product.findById(data.productId).then((product) => {
product.orders.push({userId:data.userId})
return ordered.save().then((updated_product, error) => {
if(error){
return false
}
return true
})
})
}catch(err){return err.message}
if(is_user_updated && is_product_updated){
return {
message: 'User checkout is successful!'
}
}
return {
message: 'Something went wrong.'
}
}

TypeError: Cannot destructure property 'err' of '(intermediate value)' as it is undefined

I have a React application with a Node.js backend.
I have this route on the backend:
router.put(
'/testimonial/:testimonialId/:action',
[authenticate, validateUser],
async (req, res) => {
if (req.params.action === 'ACCEPT') {
const { err, status, data } =
await notificationController.acceptTestimonial(
req.params.testimonialId,
req.user._id
);
res.status(status).send({ err, data });
} else if (req.params.action === 'REJECT') {
const { err, status, data } =
await notificationController.rejectTestimonial(
req.params.testimonialId,
req.user
);
res.status(status).send({ err, data });
}
}
);
These are the corresponding Controllers: (acceptTestimonial/rejectTestimonial)
const acceptTestimonial = async (testimonialId, userId) => {
try {
await Users.findOne({ _id: userId }, async function (err, creator) {
if (err) return { err, status: 404, data: null };
else {
const updatedTestimonials = creator.testimonials.map((testimonial) => {
if (testimonial._id == testimonialId) {
testimonial.status = 'PUBLISHED';
}
return testimonial;
});
creator.testimonials = updatedTestimonials;
await creator.save();
return { err: null, status: 200, data: creator };
}
});
} catch (err) {
return { err: err.toString(), status: 500, data: null };
}
};
const rejectTestimonial = async (testimonialId, userId) => {
try {
await Users.findOne({ _id: userId }, async function (err, creator) {
if (!creator)
return { err: 'Creator not found!', status: 404, data: null };
else {
const updatedTestimonials = creator.testimonials.map((testimonial) => {
if (testimonial._id === testimonialId) {
testimonial.status = 'REJECTED';
}
return testimonial;
});
creator.testimonials = updatedTestimonials;
await creator.save();
return { err: null, status: 200, data: creator };
}
});
} catch (err) {
return { err: err.toString(), status: 500, data: null };
}
};
When this route runs and performs the operations, I get this error in the console
UnhandledPromiseRejectionWarning: TypeError: Cannot destructure property 'err' of '(intermediate value)' as it is undefined.
I'm unable to figure out what the problem is, is there a problem with destructuring or passing values ?
Thanks in advance.
it is because, you aren't "returning" anything in try block of your controllers. The return statement is actually of callback function.
await is used to replace callback & promise.then so you have to return something in try block. You can achieve this like:
const rejectTestimonial = async (testimonialId, userId) => {
try {
// await Users.findOne({ _id: userId }, async function (err, creator) {
// if (!creator)
// return { err: 'Creator not found!', status: 404, data: null };
// else {
// const updatedTestimonials = creator.testimonials.map((testimonial) => {
// if (testimonial._id === testimonialId) {
// testimonial.status = 'REJECTED';
// }
// return testimonial;
// });
// creator.testimonials = updatedTestimonials;
// await creator.save();
// return { err: null, status: 200, data: creator };
// }
// });
// 👆 instead of this
// 👇 do this
const creator = await Users.findOne({ _id: userId }); // for "_id", you can also simply do: await User.findById(userId);
if (!creator)
return { err: 'Creator not found!', status: 404, data: null };
// creator.testimonials.forEach((testimonial) => {
// if (testimonial._id === testimonialId)
// testimonial.status = 'REJECTED';
// });
const updatedTestimonials = creator.testimonials.map((testimonial) => {
if (testimonial._id === testimonialId)
testimonial.status = 'REJECTED';
return testimonial;
});
creator.testimonials = updatedTestimonials;
await creator.save();
return { err: null, status: 200, data: creator };
} catch (err) {
return { err: err.toString(), status: 500, data: null };
}
}
Here your controller is returning something in both try & catch cases!
I have this function
const deleteMsg = async (userId, messagesWith, messageId) => {
try {
const user = await Chat.findOne({ user: userId });
const chat = user.chats.find(
chat => chat.messagesWith.toString() === messagesWith,
);
if (!chat) {
return;
}
const messageToDelete = chat.messages.find(
message => message._id.toString() === messageId,
);
if (!messageToDelete) return;
if (messageToDelete.sender.toString() !== userId) {
return;
}
const indexOf = chat.messages
.map(m => m._id.toString())
.indexOf(messageToDelete._id.toString());
await chat.messages.splice(indexOf, 1);
await user.save();
return { success: true };
} catch (error) {
console.error(error);
return { success: false };
}
};
and calling it
const { success } = await deleteMsg(userId, messagesWith, messageId);
getting this error though
Cannot destructure property 'success' of '(intermediate value)' as it is undefined.

Firebase function not returning value

I am trying to do some operations using oncall function where,
I am first checking if user exists in database, then if he exists then do some operations like updating the DB.
well the function is working as expected and updating the DB as well, but its returning response as null so I can't tell what exactly happening.
exports.populateCart = functions.https.onCall((data, context) => {
const user = context.auth.uid;
DB.collection('users').doc(user).get().then((usr_resp) => {
if (usr_resp.exists) {
DB.collection('products').doc(data.productKey).get().then((prod_res) => {
DB.collection('carts').add({
//some data
}).then(() => {
return {
response: 'CART UPDATED'
};
}).catch((carts_err) => {
return {
response: 'ERROR WHILE POPULATING CART : ' + carts_err
}
});
}).catch((prod_err) => {
return {
response: 'ERROR WHILE FETCHING PRODUCT : ' + prod_err
};
});
}
else {
return {
response: 'USER DOES NOT EXISTS OR USER NOT AUTHENTICATED'
};
}
}).catch((usr_err) => {
return {
response: 'ERROR WHILE FETCHING USER : ' + usr_err
};
});
});
There is one more similar question on stack overflow, where the solution is proposed to use,
reject(err);
resolve(lists);
methods, Please if the solution is using above methods, then please explain the use cases of this method in detail and if there are more methods like this please explain them as well.
Firebase function not returning data
You need to return every promise that you are running:
exports.populateCart = functions.https.onCall((data, context) => {
const user = context.auth.uid;
return DB.collection('users').doc(user).get().then((usr_resp) => {
if (usr_resp.exists) {
return DB.collection('products').doc(data.productKey).get().then((prod_res) => {
return DB.collection('carts').add({
//some data
}).then(() => {
return {
response: 'CART UPDATED'
};
}).catch((carts_err) => {
return {
response: 'ERROR WHILE POPULATING CART : ' + carts_err
}
});
}).catch((prod_err) => {
return {
response: 'ERROR WHILE FETCHING PRODUCT : ' + prod_err
};
});
}
else {
return {
response: 'USER DOES NOT EXISTS OR USER NOT AUTHENTICATED'
};
}
}).catch((usr_err) => {
return {
response: 'ERROR WHILE FETCHING USER : ' + usr_err
};
});
});
Try copying the above code. Also using async functions will make it look better like this:
exports.populateCart = functions.https.onCall(async (data, context) => {
try {
const usr_resp = await DB.collection('users').doc(user).get()
if (!usr_resp.exists) throw new Error("USER DOES NOT EXISTS OR USER NOT AUTHENTICATED")
const prod_res = await DB.collection('products').doc(data.productKey).get()
await DB.collection('carts').add({ . someData . })
return { response: "Cart Updated" }
} catch (e) {
console.log(e)
return { response: e }
}
});
You are not returning your promise. (see line 3 below)
exports.populateCart = functions.https.onCall((data, context) => {
const user = context.auth.uid;
// add return here before Db.collection()
return DB.collection('users').doc(user).get().then((usr_resp) => {
if (usr_resp.exists) {
return DB.collection('products').doc(data.productKey).get().then((prod_res) => {
return DB.collection('carts').add({
//some data
}).then(() => {
return {
response: 'CART UPDATED'
};
}).catch((carts_err) => {
return {
response: 'ERROR WHILE POPULATING CART : ' + carts_err
}
});
}).catch((prod_err) => {
return {
response: 'ERROR WHILE FETCHING PRODUCT : ' + prod_err
};
});
}
else {
return {
response: 'USER DOES NOT EXISTS OR USER NOT AUTHENTICATED'
};
}
}).catch((usr_err) => {
return {
response: 'ERROR WHILE FETCHING USER : ' + usr_err
};
});
});

If statement in nodejs not executing in order

Below is controller.js script. I am facing hard time to go inside if loop "if(changeUserToSellerFlag == 1)" because this if statement is executed much earlier than this if statement "if (results.Name == "Customer")". I am not sure why the order of execution is not done line by line.
const { updateUserSellerStatus } = require("./seller.model.js");
const { genSaltSync, hashSync } = require("bcrypt");
const userid = require("../auth/token_validation.js");
const {
updateUserRoleAfterSellerApproval,
getRoleName,
} = require("../users/user.service.js");
module.exports = {
sellerVerify: (req, res) => {
var sellerStatusName;
var changeUserToSellerFlag = 0; // this flag determines if user to seller update is needed or not
approvedByName = req.fullName; //get full name from token_validation.js
approvedByEmail = req.email; //get email from token_validation.js
console.log("Request body is below");
console.log(req.body); // contains body sent by postman
updateUserSellerStatus(
req.body,
approvedByName,
approvedByEmail,
(err, results) => {
if (err) {
console.log(err);
return res.status(500).json({
success: 0,
message: err,
});
}
if (!results) {
console.log(results);
return res.json({
success: 0,
message: err,
});
}
if (req.body.sellerStatus == 3) {
sellerStatusName = "Rejected";
} else if (req.body.sellerStatus == 2) {
sellerStatusName = "Completed";
} else if (req.body.sellerStatus == 1) {
sellerStatusName = "Pending";
}
//verify if user is a seller or not
if (req.userId) {
getRoleName(req.userId, (err, results) => {
console.log("check rolename gettign below");
console.log(results);
if (results.Name == "Customer") {
console.log("User is Customer");
changeUserToSellerFlag = 1;
console.log("flag is :" + changeUserToSellerFlag);
} else if (results.Name == "Seller") {
console.log("User is Seller");
changeUserToSellerFlag = 0;
}
if (err) {
console.log(err);
return res.status(500).json({
success: 0,
message: err,
});
}
});
}
console.log("see flag changed here ", changeUserToSellerFlag);
if (changeUserToSellerFlag == 1) {
console.log("i am here");
//update userrole to seller only if user is not a seller earlier
updateUserRoleAfterSellerApproval(
req.userId,
req.roleId,
(err, results) => {
console.log("result details are bwlo");
console.log(results);
if (err) {
console.log(err);
return res.status(500).json({
success: 0,
message: err,
});
}
if (!results) {
console.log(results);
return res.json({
success: 0,
message: err,
});
}
console.log("Update into UserRole Completed successfully");
},
);
} else {
console.log(
"User is already a seller and dont need to update userrole table",
);
}
console.log(sellerStatusName);
return res.status(200).json({
success: 1,
status: sellerStatusName,
});
},
);
},
};
Below is console output
Request body is below
{ sellerId: 122, sellerStatus: 2 }
see flag changed here 0
User is already a seller and dont need to update userrole table
Completed
check rolename gettign below
TextRow { Name: 'Customer', RoleId: 2 }
User is Customer
flag is :1
where "User is already a seller and dont need to update userrole table" is executed first before "flag is :1"
to me it looks as if you're treating asynchronous code as if it was synchronous. At the top of the function you are calling parts of the code that are asynchronous, like for example every database query is generally async call.
getRoleName(req.userId, (err, results) //i assume this is an async call
process will not wait for the above code to finish before proceeding forward with its execution because it is written synchronously. So next instructions that it will execute are:
console.log('see flag changed here ', changeUserToSellerFlag);//0
if(changeUserToSellerFlag == 1)//0 --> false
}else{console.log("User is already a seller and dont need to update userrole table");}//so these 3 orders are executed immediately.
after which the async call from (i assume)
getRoleName(req.userId, (err, results)
will have finished and the proper callback will be called.
as a potential solution:
I would either wait for any database call to finish before proceeding. You can use async - await call, other solutions are also usage of Promises and of course making a callback hell.
If we use callback because you are already using them it would look something like this:
updateUserSellerStatus(
req.body,
approvedByName,
approvedByEmail,
(err, results) => {
if (err) {
console.log(err);
return res.status(500).json({
success: 0,
message: err,
});
}
if (!results) {
console.log(results);
return res.json({
success: 0,
message: err,
});
}
if (req.body.sellerStatus == 3) {
sellerStatusName = "Rejected";
} else if (req.body.sellerStatus == 2) {
sellerStatusName = "Completed";
} else if (req.body.sellerStatus == 1) {
sellerStatusName = "Pending";
}
//verify if user is a seller or not
if (req.userId) {
getRoleName(req.userId, (err, results) => {
console.log('check rolename gettign below');
console.log(results);
if (results.Name == "Customer") {
console.log("User is Customer");
changeUserToSellerFlag = 1;
console.log("flag is :" + changeUserToSellerFlag);
} else if (results.Name == "Seller") {
console.log("User is Seller");
changeUserToSellerFlag = 0;
}
console.log('see flag changed here ', changeUserToSellerFlag);
if (changeUserToSellerFlag == 1) {
console.log("i am here");
//update userrole to seller only if user is not a seller earlier
updateUserRoleAfterSellerApproval(
req.userId,
req.roleId,
(err, results) => {
console.log("result details are bwlo");
console.log(results);
if (err) {
console.log(err);
return res.status(500).json({
success: 0,
message: err,
});
}
if (!results) {
console.log(results);
return res.json({
success: 0,
message: err,
});
}
console.log("Update into UserRole Completed successfully");
}
);
} else {
console.log("User is already a seller and dont need to update userrole table");
}
console.log(sellerStatusName);
return res.status(200).json({
success: 1,
status: sellerStatusName,
});
}
if (err) {
console.log(err);
return res.status(500).json({
success: 0,
message: err,
});
}
});
}
);
},
};
I just moved the code which was below the
console.log('see flag changed here ', changeUserToSellerFlag);
inside the first callback method.
I'd recommend refactoring the callback-hell asynchronicity to promises.
Happily, util.promisify in Node's util library makes it super easy to do that for functions that are callback-async.
You end up with something like this:
const { promisify } = require("util");
const { updateUserSellerStatus } = require("./seller.model.js");
const userid = require("../auth/token_validation.js");
const {
updateUserRoleAfterSellerApproval,
getRoleName,
} = require("../users/user.service.js");
const updateUserSellerStatusP = promisify(updateUserSellerStatus);
const getRoleNameP = promisify(getRoleName);
const updateUserRoleAfterSellerApprovalP = promisify(
updateUserRoleAfterSellerApproval,
);
async function sellerVerify(req) {
var sellerStatusName;
var changeUserToSellerFlag = 0; // this flag determines if user to seller update is needed or not
switch (req.body.sellerStatus) {
case 3:
sellerStatusName = "Rejected";
break;
case 2:
sellerStatusName = "Completed";
break;
case 1:
sellerStatusName = "Pending";
break;
}
const results = await updateUserSellerStatusP(
req.body,
req.fullName,
req.email,
);
if (!results) throw new Error("No results from UUSS");
//verify if user is a seller or not
if (req.userId) {
const roleName = await getRoleNameP(req.userId);
if (roleName.Name === "Customer") {
changeUserToSellerFlag = 1;
} else if (roleName.Name === "Seller") {
changeUserToSellerFlag = 0;
}
}
if (changeUserToSellerFlag) {
console.log("i am here");
//update userrole to seller only if user is not a seller earlier
const results = await updateUserRoleAfterSellerApprovalP(
req.userId,
req.roleId,
);
console.log(results);
if (!results) throw new Error("UURASP results missing");
console.log("Update into UserRole Completed successfully");
} else {
console.log(
"User is already a seller and dont need to update userrole table",
);
}
console.log(sellerStatusName);
return {
success: 1,
status: sellerStatusName,
};
}
module.exports = {
sellerVerify: async (req, res) => {
try {
const result = await sellerVerify(req);
return res.json(result);
} catch (err) {
console.error(err);
return res.status(500).json({
success: 0,
message: err,
});
}
},
};

Callback error handler didn't stop execute function

I'm trying to develop an API post, in middle execution I have validation such as check name already in use or not. I set error handler callback, it successfully send response 'Already registered', but when I checked to CLI, it show error
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
I dont know whats wrong, I use this error handler in the past and it seems look ok.
Here is my code in router:
createUserAccount: async function (req, res) {
const programData = req.body;
try {
await service.create(programData, function (code, err, result) {
if (err) {
if(code === 409){
res.status(HTTPSTATUS.CONFLICT).send(err.message);
} else {
res.status(HTTPSTATUS.BAD_REQUEST).send(err.message);
}
} else {
res.status(HTTPSTATUS.CREATED).json(result);
}
})
} catch (e) {
console.log(e)
res.status(HTTPSTATUS.BAD_REQUEST).json("Failed.");
}
Here is my function in my service:
const config = require('#configs/config.json')
const sequelize = require('sequelize');
const SEQUELIZE = new sequelize(config[env]);
module.exports = {
createAccount: async (name, password, callback) => {
try {
let check,
institution_id;
const checkName = await Profile.count(
{
where: {
name: name
}
}
);
//result checkName = 1
if(checkName > 0){
//then successfully execute this condition and
return callback(409, 'Already registered.', null);
//this show in console ----> POST /API/v1/user/profile 409 616.152 ms - 31
}
await Login.create({
username: email,
password: password
}).then(resLogin => {
const response = {
id: resLogin.id,
}
callback(201, null, response);
}).catch( error => {
callback(400, error, null);
})
} catch (e) {
callback(400, e, null);
}
},
create: async (payload, callback) => {
let loginID = null;
let {
profile,
address
} = payload;
let {
name,
email,
password
} = profile;
try {
await module.exports.createAccount(name, password, function (code, error, result) {
if(error){
const res = {message: error};
//what I need is the execution is end in here
return callback(code, res, null);
}
loginID = result.id;
});
//but the fact is it still execute this whole function if got callback error from createAccount()
let transaction = await SEQUELIZE.transaction();
await Address.create(address, {transaction})
.then( async resAddress => {
await transaction.commit();
return callback(201, null, resProfile);
}).catch(async e => {
return callback(400, e, null);
})
} catch (e) {
console.log(e);
callback(e, null);
}
};

Resources