Invalid JSON when calling Node 8.10 Lambda - node.js

I am using lambda with cognito to write to dynamoDB after a successful login.
Node 8.10 has a different layout with the promise and asycn/await. the callback(null, event) return is not working for my. Anyone now how to solve the problem of Invalid lambda function output : Invalid JSON with node 8.10.
// Load the AWS SDK for Node.js
var AWS = require('aws-sdk');
// Set the region
//AWS.config.update({region: 'REGION'});
// Create DynamoDB document client
var docClient = new AWS.DynamoDB.DocumentClient({apiVersion: '2012-08-10'});
exports.myHandler = async (event, context, callback) => {
// TODO implement
console.log ("Authentication successful");
console.log ("Trigger function =", event.triggerSource);
console.log ("User pool = ", event.userPoolId);
console.log ("App client ID = ", event.callerContext.clientId);
console.log ("User ID = ", event.userName);
const params = {
TableName: 'xxxx',
Item: {
'userId': event.userName,
'systemUpdateDate': new Date().toJSON()
}
};
let putItem = new Promise((res, rej) => {
docClient.put(params, function(err, data) {
if (err) {
console.log("Error", err);
} else {
console.log("Success", data);
}
});
});
const result = await putItem;
console.log(result);
// Return to Amazon Cognito
callback(null, event);
};
thanks

With the suggested Node 8 approach of async/await you should use the following approach to structuring your function:
async function handler(event) {
const response = doSomethingAndReturnAJavascriptObject();
return response;
}
You're getting that error because whatever you're returning isn't something that can be parsed as a JSON object.
Without seeing your code it's hard to debug further. I expect that you might accidentally not be awaiting a .promise() version of a dynamo/cognito API call, which is causing you to return a Promise instead of a result.
n.b. you can still use the 'old' callback() method with Node 8 if you find it easier.

Related

Lambda function not pushing data into DynamoDB table

I'm running a NodeJS lambda function which is triggered by API Gateway.
My goal is to push the data and then send a status response. I think the lambda stops running before the insertData function finishes its execution, because sometimes it works but in most requests it doesn't.
Could someone lend a hand on this?
Here is my code:
// Set a table name that we can use later on
const tableName = "InterestRates"
// Load the AWS SDK for Node.js
var AWS = require('aws-sdk');
// Set the region
AWS.config.update({region: 'us-east-1'});
// Create the DynamoDB service object
var ddb = new AWS.DynamoDB({apiVersion: '2012-08-10'});
exports.handler = async (event) => {
// TODO implement
console.log(">>> Running LoanInterestRates")
if(event['resource'] == '/rates'){
if(event.httpMethod === 'POST'){
return newRate(event);
}
}
};
function insertData(params){
let status;
// Call DynamoDB to add the item to the table
ddb.putItem(params, function(err, data) {
if (err) {
status = "Error";
} else {
status = "Success";
}
});
return status
}
function newRate (event){
const newRate = JSON.parse(event.body);
var params = {
TableName: 'InterestRates',
Item: {
'termlength' : {N: newRate["length"]},
'InterestRate': {S: newRate["rate"]}
}
};
let addNewRate = insertData(params);
return {
statusCode: 200,
body: JSON.stringify({
response: addNewRate
})
}
}
I also tried using Async/Await but it didn't work.
You lambda function is Async but your code is not. You need to await the completion of your function newRate which in turn should also await the function inserData which should also await your DDB request.
I would advise you to do one of two things:
Learn how JS Async nature works and ensure you understand when you need to await.
Use a synchronous programming language like Python/Boto3 where you will not run into such issues.

Why does my Node.js AWS Lambda Function Only Work Every Other Time?

I have a Node.js Lambda function that makes a copy of a snapshot. The problem is that it only works every other time it is invoked. I think the problem is something to do with my not handling the asynchronous part of the code properly via async / await. But I can’t figure out what the problem is.
No error is ever caught. I've set the timeout value to 35 seconds which should be plenty. The logged output is identical, whether the snapshot is created or not.
But the snapshot is only created the second time I run the function!?
Can anyone tell me what is going on? Thanks.
Using the latest version of Node.js available in AWS.
var AWS = require("aws-sdk");
AWS.config.update({region: 'eu-west-2'});
const ec2 = new AWS.EC2();
const dst_account = "xxxxxxxxxxxx";
const src_account = "yyyyyyyyyyyy";
async function get_all_snapshots(owner){
console.log("*** get_all_snapshots() entered");
var params = {
Filters: [{
Name: "status", Values: [ "completed" ]
}],
MaxResults: 5, // Minimum value, as just need the last one.
OwnerIds: [ owner ]
}; // end params
try {
var snapshots = await ec2.describeSnapshots(params).promise();
return snapshots;
} catch (err) {
throw Error(err);
}
}
async function copy_snapshot(id){
console.log("*** copy_snapshot() entered", id);
var params = {
Description: "Snapshot created by Lambda Function",
DestinationRegion: "eu-west-2",
SourceRegion: "eu-west-2",
SourceSnapshotId: id
}; // end params
try {
var ss = await ec2.copySnapshot(params).promise();
console.log("*** ec2.copySnapshot() call completed. ss: ", ss); // THIS NEVER APPEARS In The LOGS
return ss;
} catch (err) {
console.log("!!! copy_snapshots() Throwing Error: ", err);
throw Error(err); // TODO: throwing for now, but could this be handled better?
}
}
exports.handler = async (event) => {
return get_all_snapshots(src_account)
.then(snapshots => {
copy_snapshot(snapshots.Snapshots[0].SnapshotId) // *** Add return here to fix ***
.then(r =>{
console.log("**new ss:", r); // THIS NEVER APPEARS IN THE LOGS
})
console.log("*** exports.handler() Ending");
})
.catch((err)=>{
console.log("*** get_all_snapshots() Error: ",err);
}); // End get_snapshots()
};

AWS cognito: adminUpdateUserAttributes not working and not giving an error , am i missing something?

I can't get adminUpdateUserAttributes for Cognito to work. The cli works and I can have the user add/changed them not desired but wanted to see it working.
I'm using the AmazonCognitoPowerUser an AWS managed policy on the lambda function and the lambda is triggering, is there something I'm missing this sounds and looks easy but it's just not working.
also is there a way to get the default Created date without making my own.
const AWS = require('aws-sdk');
const cognitoidentityserviceprovider = new AWS.CognitoIdentityServiceProvider();
exports.handler = async (event) => {
cognitoidentityserviceprovider.adminUpdateUserAttributes(
{
UserAttributes: [
{
Name: 'custom:Date_Created',
Value: new Date().toString()
}
....
],
UserPoolId: " the correctpool id",
Username: "dagTest"
},
function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else console.log(data);
}
)};
// no errors and returns nothing as it says it should.
I guess it is because you are not waiting for the result and the lambda is terminating after adminUpdateUserAttributes() is called and dows not wait until it is returning.
I would suggest that you change to promise based calling and do a try/catch
exports.handler = async (event) => {
try{
// no callback here
const data = await cognitoidentityserviceprovider
.adminUpdateUserAttributes(attributes)
.promise()
console.log('success', data)
} catch(error) {
console.error('error', error)
}
)}
#thopaw The code is correct but didn't work for me as intended. I was still getting Auth Error in the front end even through the custom attributes were updated successfully in the Cognito AWS Console. I had to add context.done(null,event); in order to return the control to Cognito after the execution of lambda. So the updated one could be,
exports.handler = async (event, context) => {
try{
const data = await cognitoidentityserviceprovider
.adminUpdateUserAttributes(attributes)
.promise()
console.log('success', data)
} catch(error) {
console.error('error', error)
}
context.done(null,event);
)}

AWS lambda javascript IAM Role

According to the AWS Lambda documentation, a Lambda function written in Node will use the credentials of the IAM role assigned to the function. The same is true for functions written in Python. I wrote a function in Node, and it is getting an unauthorized error. The same function in Python, using the same configuration, works. I am using the official AWS SDK in both cases.
The fact that it works in Python and not in Node tells me that it is not a configuration issue. If hard code credentials into the Node function, it works, so I know the function logic works.
Any ideas?
Code that is now working (but did not yesterday!)
// Load the AWS SDK for Node.js
const AWS = require('aws-sdk');
exports.handler = async (event) => {
const EC2 = new AWS.EC2();
var instanceId = "i-xxxxxxxxxxx";
var params = {
InstanceIds: [instanceId],
DryRun: false
};
var response = {
status: 200
};
try {
const startInstance = await EC2.startInstances(params, function(err, data) {
if (err) {
console.log("error: " + err.code);
response.status = 403;
response.error = err.code;
} else if (data) {
console.log(data);
response.instanceInfo = data;
}
}).promise();
} catch(err) {
console.log(err.code);
}
return response;
};

Response from AWS lambda function called from another lambda function is always null

I have two lambda functions and I need to call a function named sendHealthData from a function named receiveHealthData. I'm using Node.JS 8.10 and the Serverless framework.
Here's the code to receiveHealthData:
const env = process.env;
const aws = require("aws-sdk");
const Lambda = new aws.Lambda();
const S3 = new aws.S3();
exports.main = (event, context, callback) => {
const params = {
FunctionName: "sendHealthData",
InvocationType: "RequestResponse",
Payload: JSON.stringify(event)
}
Lambda.invoke(params, function(error, remainingHealthData) {
if (error) {
reject(error);
}
else {
console.log("Remaining: " + remainingHealthData["Payload"]);
if (!remainingHealthData["Payload"]) {
reject(new Error("Payload is null"));
}
else {
resolve(remainingHealthData);
}
}
});
}
And this is sendHealthData:
exports.main = async (event, context, callback) => {
callback(null, "Sent Health Data!");
}
remainingHealthData["Payload"] is null everytime.
The output of console.log(JSON.stringify(remainingHealthData)) is:
{"StatusCode":200,"Payload":'null'}
When I invoke sendHealthData through serverless invoke --function sendHealthData I get the expected result: "Sent Health Data!"
I got the expected response only once: when I changed the timeout of the sendHealthData function. But the strange thing is that I changed it to a smaller value. It was 10 and I changed it to 6.
The issue is that you are using RequestResponse as InvocationType but your sendHealthData AWS Lambda doesn't return a valid JSON (just a string).
A small quote out of the documentation says:
Payload — (Buffer, Typed Array, Blob, String)
It is the JSON representation of the object returned by the Lambda function. This is present only if the invocation type is RequestResponse.
So as soon as you change the return value of your sendHealthData AWS Lambda to the following it should work as you expect:
exports.main = async (event, context, callback) => {
callback(null, {
"message": "Sent Health Data!"
});
}

Resources