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.
Related
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
I have tried on both Async Handlers and Non-Async Handlers ways,
to implement dynamodb putItem method. it returned an invalid response.
Its works for commented setTimeout function.
I tried by promisify the dynomodb putItem method in Non-Async Handler way as mentioned and official documentation https://docs.aws.amazon.com/lambda/latest/dg/nodejs-handler.html. But still no luck.
can some one point me out the issue on code?
const AWS = require('aws-sdk');
const dynamodb = new AWS.DynamoDB({
region: 'ap-south-1',
apiVersion: '2012-08-10'
});
exports.lambdaHandler = async function(event) {
const promise = new Promise(function(resolve, reject){
// setTimeout(function(){
// console.log("resolvedx")
// resolve({statusCode: 200, body: "resolvedx"})
// }, 200)
dynamodb.putItem({
TableName: 'CUSTOMER_LIST',
Item: {
'CUSTOMER_ID': { N: '012' },
'CUSTOMER_NAME': { S: 'zzzza' }
}
}
, function(err, data) {
if (err) {
console.log("err", err);
reject(JSON.stringify({statusCode:200, body:err}));
} else {
console.log("success", data);
resolve(JSON.stringify({statusCode:200, body:data}));
}
})
})
return promise
}
as Non-Async Handlers
exports.lambdaHandlerx = (event, context, callback) => {
const dbPromise = () => new Promise((resolve, reject) => {
console.log("inside db promise")
dynamodb.putItem({
TableName: 'CUSTOMER_LIST',
Item: {
'CUSTOMER_ID': { N: '023' },
'CUSTOMER_NAME': { S: 'asdddwa' }
}
}
, function(err, data) {
if (err) {
console.log("err", err);
reject(err);
} else {
console.log("success", data);
resolve(data);
}
})
})
Promise.all([dbPromise()]).then(data => {
console.log("then", data)
callback(null, {
'statusCode': 200,
'body': JSON.stringify({
message: "dataxz"+ JSON.stringify(data)
})
})
}
).catch(e => {
callback(null, {
'statusCode': 200,
'body': JSON.stringify({
message: 'err'
})
})
})
}
Output
Function returned an invalid response (must include one of: body, headers, multiValueHeaders or statusCode in the response object). Response received:
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.
I have created a nodejs/express api, which is a wrapper around another api.
I am making async calls with try and catch. I am wondering in the inner async call if it catches an error will this error be caught by the outer async call.
The transaction.controller is my api which calls the transaction.repository to an external api. The function getTransactionResult is throwing an error in the catch part. However, this does NOT loop back to the catch part of my show function.
router.ts
this.router.get('/:id', this.controller.show.bind(this.controller));
transaction.controller.ts
public async show(req: Request, res: Response): Promise<any> {
const params = req.params;
const token = req.headers.token;
let transaction;
try {
transaction = await this.transactionRepo.getTransactionResult(params.id, token);
console.log("instead carries on here"); // 2
if (transaction.success === false) {
return res.status(404).json({
success: false,
status: 404,
data: transaction,
message: "Failed to retrieve transaction result"
});
}
return res.status(200).json({
success: true,
status: 200,
data: transaction,
message: "Successfully retrieved transaction result"
});
} catch (err) {
//console.log("Does not call this");
return res.status(500).json({
success: false,
status: 400,
data: err,
message: "The server threw an unexpected error",
});
}
transaction.repository.ts
public async getTransactionResult(transactionId: string, token: string) {
const url = this.config.api_url + "/api/transactions/" + transactionId + "/summary";
const options = {
uri: url,
headers: {
'token': token
},
body: {
},
json: true,
resolveWithFullResponse: true
}
let result;
try {
result = await request.get(options);
if (result.statusCode !== 200) {
return { "success": false, data: result }
}
return { "success": true, data: result }
} catch (err) {
console.log("CAUGHT ERROR"); // 1
return err;
}
}
You need to rethrow the error not return it.
By doing return err you are resolving the Promise which mean the async operation succeeded. Hence why your out try-catch in transaction.controller.ts does not catch anything.
Either:
Don't catch the error and let it bubble up
Rethrow the error
first time when i make a request its working fine, but when i make the request again without restarting the server, its going time out and returning some promise error
following is the code and error
module.exports.getOne = (event, context, callback) => {
context.callbackWaitsForEmptyEventLoop = false;
db.once('open', () => {
Client.findOne({name:{ $regex : new RegExp(event.pathParameters.name, "i") }})
.then(client => callback(null, {
statusCode: 200,
body: JSON.stringify(client)
}))
.catch(err => callback(null, {
statusCode: err.statusCode || 500,
headers: { 'Content-Type': 'text/plain' },
body: 'Could not fetch the note.'
}))
.finally(() => {
// Close db connection or node event loop won't exit , and lambda will timeout
db.close();
});
});
};
Error:
(node:3273) UnhandledPromiseRejectionWarning: Error: Cannot stop server while in stopping state
The issue is that you aren't completing the call by calling callback so it thinks that your getOne() function isn't finished.
Take a look at the sample code that serverless provides when you setup a new serverless app with their template
module.exports.hello = (event, context, callback) => {
const response = {
statusCode: 200,
body: JSON.stringify({
message: 'Go Serverless v1.0! Your function executed successfully!',
input: event,
}),
};
callback(null, response);
};