How to avoid catch redundancy in express node.js - node.js

I have multiple calls in a process inside in a Route, I find myself obliged to duplicate the "catch" process several times :
Marque.one(createOrder.Order_marque).then(function(m){
Forfaits.oneByIdExt(id).then(function(forfait) {
createOrder["donneur_ordre_id"] = parseInt(forfait[0].donneur_ordre_id)
createOrder["structure_juridique_id"] = parseInt(forfait[0].structure_juridique_id)
OrderEntries.insertOrderEntries(m[0].Marque, idPlan, createUser, createOrder, req.user.id).then(function (data) {
Order.createOrder(createOrder, createUser, req.body.Cart)
.then(function (num_cmd) {
if(forfait[0].tid != null){
OrderTP.insert(createTP).then(function (){
res.status(200).json({return: 200, returnLabel: 'OK', data: {num_cmd}});
})
}else {
res.status(200).json({return: 200, returnLabel: 'OK', data: {num_cmd}});
}
}).catch(function (error) {
res.status(500).json({return: 500, returnLabel: 'KO', data:{}});
});
}).catch(function (error) {
res.status(500).json({return: 500, returnLabel: 'KO', data:{}});
});
}).catch(function (error) {
res.status(500).json({return: 500, returnLabel: 'KO', data:{}});
});
}).catch(function (error) {
res.status(500).json({return: 500, returnLabel: 'KO', data:{}});
});
At the beginning I only put the last one but it does not catch the other errors which follow in the other call, how to avoid such a replication of the same code which is really not beautiful ?
Thank You

use async await and wrap your code in try catch block.
example:
async handlePromise(){
try {
const fist_prmise = await FistPromise();
const second_promise = await SecondPromise();
}catch(e){
console.log(e)
}
}
second promise waiting until first promise resolve

Related

Node.js: Function not awaiting for a promise

I'm having an issue with a function not awaiting for a promise.
I have a route with a post method, that pushes the body to the controller.
The controller, will then send it to the middleware to actually process the save to a MongoDB.
The middleware will return the the promised object back to the controller.
The controller is finishing with out awaiting the completion of the middleware.
The middleware is async, and the controller has an await and then a .then even following further.
Thoughts?
Controller
export async function createPlayer(req,res) {
//creates a Player in the database
try {
let results = '';
results = await PlayerFunction.createPlayer(req.body)
.then(console.log(results))
.then(res.status(200).send(results))
} catch (error) {
log_error('Errored trying to create Player in controller.', error);
res.status(404).send('Error Has Occured. An Admin has been contacted.');
}
};
Middleware
export async function createPlayer(req_body) {
//creates a Player in the database
try {
//set new player object
let new_Player = new Player(req_body);
new_Player.save((error) => {
if (error) {
log_error('Trying to create a Player.', error)
return { success: 'error', body: 'Error Has Occured. An Admin has been contacted.' };
} else {
console.log(new_Player);
return { success: true, body: new_Player };
};
});
} catch (error) {
log_error('Errored trying to create a player.', error);
return { success: 'error', body: 'Error Has Occured. An Admin has been contacted.' };
}
};
I tried to use .then promises to catch the returned results from the middleware and then return the results to the user.
What I have found is that the .save((error) => function doesn't follow the await made by the call it self. If you remove the error handling on the Save and rely on the catch in the overall try catch it will follow the await.
Controller:
export async function createPlayer(req,res) {
//creates a Player in the database
try {
res.status(200).send(await PlayerFunction.createPlayer(req.body));
} catch (error) {
log_error('Errored trying to create Player in controller.', error);
res.status(404).send('Error Has Occured. An Admin has been contacted.');
}
};
Middlewear
export async function createPlayer(req_body) {
//creates a Player in the database
try {
let new_Player = new Player(req_body);
await new_Player.save();
return { success: true, body: new_Player };
} catch (error) {
log_error('Errored trying to create a player.', error);
return { success: 'error', body: 'Error Has Occured. An Admin has been contacted.' };
}
};
In the async function needs to return promise-based value.
A Promise which will be resolved with the value returned by the async function, or rejected with an exception thrown from, or uncaught within, the async function.
So in your middleware createPlayer() needs to return Promise-based value.
export async function createPlayer(req_body) {
//creates a Player in the database
try {
//set new player object
let new_Player = new Player(req_body);
new_Player.save((error) => {
if (error) {
log_error('Trying to create a Player.', error)
return Promise.reject(JSON.stringify({ success: 'error', body: 'Error Has Occured. An Admin has been contacted.' }));
} else {
console.log(new_Player);
return Promise.resolve(JSON.stringify({ success: true, body: new_Player }));
};
});
} catch (error) {
log_error('Errored trying to create a player.', error);
return Promise.reject(JSON.stringify({ success: 'error', body: 'Error Has Occured. An Admin has been contacted.' }));
}
};

cannot set headers after they are sent to the client when i use mongoose remove function

when i use this code
activecode.remove(err => {
return res.status(500).json("error message ")
});
get the error cannot set headers after they are sent to the client
when i remove the above code it works without error
this is my code
async activeUser(req, res, next) {
try {
const code = req.params.code;
const activecode = await ActiveCode.findOne({
code
}).gt("expire", new Date()).populate("user").limit(1).exec();
if (activecode) {
if (activecode.used) {
return res.status(400).json({
message: "از این لینک قبلا استفاده شده است"
})
} else {
activecode.used = true;
activecode.save(err => {
if (err) {
return res.status(500).json({
message: "خطایی در فعال سازی رخ داد"
})
};
});
if (activecode.user) {
activecode.user.isActive = true;
activecode.user.save(err => {
if (err) {
return res.status(500).json({
message: "خطایی در فعال سازی رخ داد"
})
};
});
const user = {
id: activecode.user.id,
name: activecode.user.name,
email: activecode.user.email,
isActive: activecode.user.isActive
}
activecode.remove(err => {
return res.status(500).json("خطایی در فعال سازی اکانت رخ داد ")
});
return res.status(200).json({
user
});
}
}
} else {
return res.status(400).json({
message: "چنین لینکی برای فعال سازی حساب وجود ندارد"
});
}
} catch (err) {
return res.status(500).json({
message: "خطایی در فعال سازی حساب رخ داده لطفا دوباره امتحان کنید"
});
}
}
any
res.status.json
used with return
what i do for solve this problem . where my code trying to send multiple responses
Because you already have an async function with try/catch so you don't need to use .save() and .remove() with callback. You just need to use await and let the catch handle error for you.
This may help:
async activeUser(req, res, next) {
try {
const code = req.params.code;
const activecode = await ActiveCode.findOne({
code
}).gt("expire", new Date()).populate("user").limit(1).exec();
if (activecode) {
if (activecode.used) {
return res.status(400).json({
message: "از این لینک قبلا استفاده شده است"
})
} else {
activecode.used = true;
await activecode.save();
if (activecode.user) {
activecode.user.isActive = true;
await activecode.user.save();
const user = {
id: activecode.user.id,
name: activecode.user.name,
email: activecode.user.email,
isActive: activecode.user.isActive
}
await activecode.remove();
return res.status(200).json({
user
});
}
}
} else {
return res.status(400).json({
message: "چنین لینکی برای فعال سازی حساب وجود ندارد"
});
}
} catch (err) {
return res.status(500).json({
message: "خطایی در فعال سازی حساب رخ داده لطفا دوباره امتحان کنید"
});
}
}
Change this part of your code:
activecode.remove(err => {
return res.status(500).json("خطایی در فعال سازی اکانت رخ داد ")
});
return res.status(200).json({
user
});
With
activecode.remove((err, data) => {
if (err) {
return res.status(500).json("خطایی در فعال سازی اکانت رخ داد ");
} else {
return res.status(200).json({user});
}
});
The problem here your request tries to send response twice, which is not allowed.
hope this helps :)
The situation is arising because you are trying to send the response for a particular request twice which is not allowed.
Also on side note,your request route doesnt gets finished when they encouter a response(res.status().json() or res.send()) it will continue to the parse to the end of the function and if while parsing they encounter another res.send() or res.status().json() they will throw the above error.
for example
app.get('/some_route',(req,res)=>{
if("condition")
res.send('something);
else
res.send('another thing');
})
app.get('/some_route',(req,res)=>{
if("condition")
res.send('something');
res.send("another something");
})
the first example is correct but the second one is not

NodeJS , how to send response during Promise .then?

I have the following code:
User.getConfByID(userID)
.then((item)=>{
if(item.length == 0){
res.status(400).json({error:"NO_USER_FOUND"})
}else{
if(item[0].token == token){
if((Math.abs(Date.now() - item[0].conf_iat)) > tokenValid){
res.status(401).json({error: "TOKEN_INVALID"})
}else{
return mariaDBTemplates.updateOneRowTemplate("User_confirmation", {confirmed:1}, "user_id", userID)
}
}else{
res.status(401).json({error: "TOKEN_NOT_SAME"})
}
}
})
.then(()=>{
res.status(200).json({success: "CONFIRMED"})
})
.catch((err)=>{
res.status(500).json({error: err.message})
})
You see I have different kinds of error messages with different kinds of status codes. When I run this code, it always gives me this warning:
Error: Can't set headers after they are sent
I think this is because i don't "break" the Promise after sending a response right?. But how can I solve this? Any suggestions?
Cheerio
your problem is with your promise chain. in your first .then, you always set the response with res, but the next .then in the chain tries to set the response again. Note that not returning anything from a promise is the same as return Promise.resolve(undefined);.
here's how I would do it:
User.getConfByID(userID)
.then((item) => {
if(item.length == 0)
return { statusCode: 400, body: { error: "NO_USER_FOUND" } };
else {
if(item[0].token == token) {
if((Math.abs(Date.now() - item[0].conf_iat)) > tokenValid)
return { statusCode: 401, body: { error: "TOKEN_INVALID" } };
else {
//not sure what this returns, but it looks like this is
//what you're trying to return the 200 for
mariaDBTemplates.updateOneRowTemplate("User_confirmation", { confirmed: 1 }, "user_id", userID);
return { statusCode: 200, body: { success: "CONFIRMED" } };
}
} else
return { statusCode: 401, body: { error: "TOKEN_NOT_SAME" } };
}
})
.then((result) => {
res.status(result.statusCode).json(result.body);
})
.catch((err) => {
res.status(500).json({ error: err.message });
});
Also note that returning a value from a promise is the same as returning Promise.resolve(value);, and will continue the promise chain.

Server sends success even if didn't find anything

I send data from my input fields to my api:
$.ajax({
url: '/api/login',
type: 'GET',
dataType: 'json',
ContentType: 'application/json',
data: {formData},
success: (data) => {
console.log('SUCCESS')
console.log(data)
this.setState({
isInProcess: false
})
},
error: (jqXHR) => {
console.log(jqXHR)
console.log('ERROR')
this.setState({isInProcess: false})
}
})
on my server-side I have a function to see if I have required user in db:
async function findUser(data) {
try {
const user = await User.findOne({email: data.email,
password: data.password})
console.log('User was found')
return { user }
} catch (err) {
console.log('error', err)
throw err
}
}
which will be executed here:
app.get('/api/login', async (req, res) => {
const data = req.query
try {
const foundUserData = await findUser(data.formData)
return res.json(foundUserData)
} catch (err) {
return res.status(400).json(err)
}
})
It works fine, but if a user wasn't found in db i sends success anyway. Why?
await findUser(data.formData) won't throw error, return either null or user object. You may check something following
app.get('/api/login', async (req, res) => {
const data = req.query
try {
const foundUserData = await findUser(data.formData)
if(foundUserData && foundUserData.user) {
return res.json(foundUserData)
} else {
return res.status(400).json({message: 'User not found'});
}
} catch (err) {
return res.status(500).json(err)
}
})
It sends success because none of your queries error'ed, just because it didn't find anything does not mean that the query failed because it obviously succeeded in finding out if what ever you're looking for exists or not.
To send an error in case of not found you need to check if response is empty in which case you want to send error
When no user is find you get a null value. You may try to put more logic on your success parameter with that for example:
success: function (data) {
if(!!data && data != null) {
alert('Success');
} else {
alert('No data');
}
}

Using a callback inside of AWS Lambda handler

I've been struggling with trying to output the success/error of my promise chain.
I am chaining promises together like this
exports.handler = function(event, context, callback) {
Q.allSettled(init()).then(function (result) {
requestValid(event.queryStringParameters)
.then(isDuplicate)
.then(process)
.then(insertData)
.then(displayResponse)
.catch(function (error) {
// Handle any error from all above steps
console.error(
'Error: ' + error
);
callback({
statusCode: 500,
body: JSON.stringify({
message: error
}, null)
});
})
.done(function () {
console.log(
'Script Finished'
);
callback(null, {
statusCode: 200,
body: JSON.stringify({
message: 'Done'
})
});
});
});
};
I am calling Q.defer.reject(error_message); on fail and Q.defer.resolve(success_message) on success inside of the promises. If any of these promises fail, the error is being caught in .catch(function (error) {.
That's all fine but how do I return this data to the handler's callback?
Example of what I want to do, but don't how/where to put it because of the promises...
exports.handler = function (event, context, callback) {
let response = {
statusCode: 200,
body: JSON.stringify('some success or error')
};
// Return all of this back to the caller (aws lambda)
callback(null, response);
};
Thank you in advance..
Chain your promises all the way you usually do it. Return the result on the last step of the chain. catch errors at the end, and return the error if any:
exports.handler = function(event, context, callback) {
RequestIsValid(event)
.then(isDuplicate)
.then(process)
.then(insertData)
.then(getResponse)
.then(function(result) {
//result would be the returning value of getResponse.
callback(null, {
statusCode: 200,
body: JSON.stringify({
message: 'Done',
response: result
})
});
})
.catch(function (error) {
// this will show on CloudWatch
console.error(
'Error: ' + error
);
// this will be the response for the client
callback({
statusCode: 500,
body: JSON.stringify({
message: error
}, null)
});
})
// end of the function
}
That's assuming that isDuplicate, process, insertData and getResposne return a promise and the result of each can be chained to the next one.

Resources