I'm trying to invoke a code in AWS Lambda. This Lambda code has been configured with my IOT button. On running this code, I don't see any errors. Also,I don't really see the required push notification on my mobile device.
I can see this message in my console : MissingRequiredParameter: Missing required key 'Message' in params
This is my code:
'use strict';
console.log('Loading function');
var AWS = require('aws-sdk');
var sns = new AWS.SNS();
AWS.config.region = 'xxxxx';
const TopicArn = 'xxxxxxxxxxxxxxxxxxxxxxxxxx'
exports.handler = function(event, context) {
console.log("\n\nLoading handler\n\n");
console.log('Received event:', event);
const sin =
{
"default": "Start",
"APNS_SANDBOX":"{\"aps\":{\"alert\":\"Start\"}}",
"GCM": "{ \"notification\": { \"text\": \"Start\" } }"
} // for single click
const doub = {
"default": "Stop",
"APNS_SANDBOX":"{\"aps\":{\"alert\":\"Stop\"}}",
"GCM": "{ \"notification\": { \"text\": \"Stop\" } }"
} // for double click
const lon = {
"default": "SOS",
"APNS_SANDBOX":"{\"aps\":{\"alert\":\"SOS\"}}",
"GCM": "{ \"notification\": { \"text\": \"SOS\" } }"
} // for long click
var singleClick = sin[Math.floor(Math.random()*sin.length)];
var doubleClick = doub[Math.floor(Math.random()*doub.length)];
var longClick = lon[Math.floor(Math.random()*lon.length)];
var randomMessage = singleClick;
if(event.clickType == "DOUBLE")
{
randomMessage = doubleClick;
}
if(event.clickType == "LONG")
{
randomMessage = longClick;
}
sns.publish ({
Message: randomMessage,
TopicArn: TopicArn
},
function(err, data) {
if (err) {
console.log(err.stack);
return;
}
console.log('push sent');
console.log(data);
context.done(null, 'Function Finished!');
});
}
Can someone help me debug this error?
I found the answer. I had to define my variable too as a string using stringify() command or else JSON formatted message cannot be sent.
Related
I am new to AWS services and I am trying out various services provided by AWS. I have this lambda function on which I am trying to find a user with the phone number on AWS Cognito -
const AWS = require('aws-sdk');
async function findCognitoUser(userId) {
console.log('CognitoUser-FindCognitoUser');
var params = {
UserPoolId: 'poolId',
AttributesToGet: [
'phone_number','displayName'
],
Filter: `phone_number = \"${userId}\"`,
};
cognitoidentityserviceprovider.listUsers(params, function(err, data) {
if (err) {
return 'ERROR OCCURED';
}
else {
return data.Users[0].displayName;
}
});
}
module.exports = findCognitoUser;
I do get an error saying cognitoidentityserviceprovider is not defined
Here is the error on CloudWatch -
"errorType": "ReferenceError",
"errorMessage": "cognitoidentityserviceprovider is not defined",
"stack": [
"ReferenceError: cognitoidentityserviceprovider is not defined",
" at findCognitoUser (/var/task/user-queries/findCognitoUser.js:13:5)",
" at Runtime.exports.handler (/var/task/index.js:14:19)",
" at Runtime.handleOnce (/var/runtime/Runtime.js:66:25)"
]
CODE UPDATED -
const AWS = require('aws-sdk');
async function findCognitoUser(userId) {
console.log(userId);
var csp = new AWS.CognitoIdentityServiceProvider({apiVersion: '2016-04-18'});
var params = {
UserPoolId: 'poolid',
AttributesToGet: [
'phone_number','given_name'
],
Filter: `phone_number = \"${userId}\"`,
};
csp.listUsers(params, function(err, data) {
console.log(data);
if (err) {
return 'ERROR OCCURED';
}
else {
return data.Users[0].given_name;
}
});
}
module.exports = findCognitoUser;
I am trying to pull and display data from DynamoDb by using AWS Lambda function and have it display on AWS Lex. It is returning the if portion with the word "undefined" in the place where the data should be. The information is in the DynamoDB database. I am mainly using AWS servers and building this serverless Lex bot application.
AWS code Segments
const AWS = require('aws-sdk');
const db = new AWS.DynamoDB.DocumentClient({region: 'us-east-1'});
exports.handler = async (event) => {
// TODO implement
const response = {
statusCode: 200,
body: JSON.stringify('Hello from Lambda!'),
};
return response;
};
function getExamSchedule(exam2, table){
return new Promise(function(resolve){
var info = 0;
var params = {
TableName: table,
FilterExpression: "#key = :data",
ExpressionAttributeNames: {
"#key": "Resource",
},
ExpressionAttributeValues:{
":data": exam2
}
};
db.scan(params, function(err, data){
if(err){
console.log("Error: " + err);
info = 0;
} else {
console.log("Success", data);
info = {"ClassID" :data.Items[0].ClassID, "ExamDate " :data.Items[0].ExamDate,
"ExamEndTime:" :data.Items[0].ExamEndTime, "ExamLocation" :data.Items[0].ExamLocation,
"ExamStartTime" :data.Items[0].ExamStartTime};
}
resolve(info);
});
});
}
This is the portion where the issue might be occurring.
exports.handler = async (event, context, callback) => {
var exam2 = event.currentIntent.slots.ClassID;
var info = await getExamSchedule(exam2, "Final_Exams");
var res;
// if (info !== 0)
if(info != null){
res =`The exam information for ${exam2} is ${info.ClassID} Date: ${info.ExamDate}
End time: ${info.ExamEndTime} Location: ${info.ExamLocation} Start time: ${info.ExamStartTime}`;
} else {
res = `The exam is not entered into our database, please look for another exam.`;
}
callback(null, {
"dialogAction": {
"type":"Close",
"fulfillmentState": "Fulfilled",
"message":{
"contentType": "PlainText",
"content": res
}
}
});
};
Could you perhaps share some of the logs and/or stack traces that you encounter when running the code?
I want to send emails using the ses from aws from lambda. The problem is that the email is only sent some times using the same code. We don't get errors.
Here's the code:
const AWS = require('aws-sdk');
var ses = new AWS.SES();
exports.handler = async (event, context, callback) => {
context.callbackWaitsForEmptyEventLoop = false;
await new Promise((resolve, reject) => {
var params = {
Destination: {
ToAddresses: [myEmail]
},
Message: {
Body: {
Text: { Data: "Test"
}
},
Subject: { Data: "Test Email"
}
},
Source: "sourceMail"
};
ses.sendEmail(params, function (err, data) {
if (err) {
console.log(err);
context.fail(err);
} else {
console.log(data);
context.succeed(event);
}
callback(null, {err: err, data: data});
});
});
}
I would be careful with using callbackWaitsForEmptyEventLoop as it can lead to unexpected results (If this is false, any outstanding events continue to run during the next invocation.).
Can you try using this simplified version:
const AWS = require('aws-sdk');
var ses = new AWS.SES();
exports.handler = async (event, context, callback) => {
const params = {
Destination: {
ToAddresses: [myEmail],
},
Message: {
Body: {
Text: { Data: 'Test' },
},
Subject: { Data: 'Test Email' },
},
Source: 'sourceMail',
};
await ses.sendEmail(params).promise();
return event;
};
This code works just fine locally using nodejs. Images download from s3, write to file.
However, in Lambda (using nodejs 8.10) I'm getting "Internal Server Error" when testing the function with this in the Logs:
"Execution failed due to configuration error: Malformed Lambda proxy response"
I am using the lambda proxy response in the callback, but clearly some AWS SDK error with S3 is not getting caught.
I do have a role setup with S3 full access that the Lambda has access to.
What am I missing with my first Lambda function? Docs and tutorials I've followed correctly and it is not working.
const async = require('async')
const aws = require('aws-sdk')
const fs = require('fs')
const exec = require('child_process').exec
const bucket = 'mybucket'
const s3Src = 'bucket_prefix'
const s3Dst = 'new_prefix'
const local = `${__dirname}/local/`
aws.config.region = 'us-west-2'
const s3 = new aws.S3()
exports.handler = async (event, context, callback) => {
const outputImage = 'hello_world.png'
const rack = JSON.parse(event.body)
const images = my.images
async.waterfall([
function download(next) {
let downloaded = 0
let errors = false
let errorMessages = []
for (let i = 0; i < images.length; i++) {
let key = `${s3Src}/${images[i].prefix}/${images[i].image}`,
localImage = `${local}${images[i].image}`
getBucketObject(bucket, key, localImage).then(() => {
++downloaded
if (downloaded === images.length) { // js is non blocking, need to check if all images have been downloaded. If so, then go to next function
if (errors) {
next(errorMessages.join(' '))
} else {
next(null)
}
}
}).catch(error => {
errorMessages.push(`${error} - ${localImage}`)
++downloaded
errors = true
})
}
function getBucketObject(bucket, key, dest) {
return new Promise((resolve, reject) => {
let ws = fs.createWriteStream(dest)
ws.once('error', (err) => {
return reject(err)
})
ws.once('finish', () => {
return resolve(dest)
})
let s3Stream = s3.getObject({
Bucket: bucket,
Key: key
}).createReadStream()
s3Stream.pause() // Under load this will prevent first few bytes from being lost
s3Stream.on('error', (err) => {
return reject(err)
})
s3Stream.pipe(ws)
s3Stream.resume()
})
}
}
], err => {
if (err) {
let response = {
"statusCode": 400,
"headers": {
"my_header": "my_value"
},
"body": JSON.stringify(err),
"isBase64Encoded": false
}
callback(null, response)
} else {
let response = {
"statusCode": 200,
"headers": {
"my_header": "my_value"
},
"body": JSON.stringify(`<img src="${local}${outputImage}" />`),
"isBase64Encoded": false
}
callback(null, response)
}
}
)
}
Response should be always sent to callback function. Your code sends response only on error. That's why Lambda executor thinks your code fails.
BTW - should your functions in async.waterfall be separated with coma, as two tasks?
Locally, I've been running nodejs 10.10 and lambda currently is at 8.10. That is a big part I'm sure. In the end I had to remove the async. I had to move the getBucketObject function out of the waterfall. Once I made those adjustments it started working. And another issue was the downloaded images needed to go into "/tmp" directory.
const aws = require('aws-sdk')
const async = require('async')
const fs = require('fs')
const bucket = 'mybucket'
const s3Src = 'mys3src'
const local = '/tmp/'
aws.config.region = 'us-west-2'
const s3 = new aws.S3()
exports.handler = (event, context, callback) => {
const outputImage = 'hello_world.png'
async.waterfall([
function download(next) {
let downloaded = 0,
errorMessages = []
for (let i = 0; i < event['images'].length; i++) {
let key = `${s3Src}/${event['images'][i]['prefix']}/${event['images'][i]['image']}`,
localImage = `${local}${event['images'][i]['image']}`
getBucketObject(bucket, key, localImage).then(() => {
downloaded++
if (downloaded === event['images'].length) {
if (errorMessages.length > 0) {
next(errorMessages.join(' '))
} else {
console.log('All downloaded')
next(null)
}
}
}).catch(error => {
downloaded++
errorMessages.push(`${error} - ${localImage}`)
if (downloaded === event['images'].length) {
next(errorMessages.join(' '))
}
})
}
}
], err => {
if (err) {
console.error(err)
callback(null, {
"statusCode": 400,
"body": JSON.stringify(err),
"isBase64Encoded": false
})
} else {
console.log('event image created!')
callback(null, {
"statusCode": 200,
"body": JSON.stringify(`<img src="${local}${outputImage}" />`),
"isBase64Encoded": false
})
}
}
)
}
function getBucketObject(bucket, key, dest) {
return new Promise((resolve, reject) => {
let ws = fs.createWriteStream(dest)
ws.once('error', (err) => {
return reject(err)
})
ws.once('finish', () => {
return resolve(dest)
})
let s3Stream = s3.getObject({
Bucket: bucket,
Key: key
}).createReadStream()
s3Stream.pause() // Under load this will prevent first few bytes from being lost
s3Stream.on('error', (err) => {
return reject(err)
})
s3Stream.pipe(ws)
s3Stream.resume()
})
}
I've been trying to get push notifications to work with my Parse application. I tried to do so my adding the below code into my Parse server.js file but my server does not start up again when this code is contained inside of the file. I have my p12 file available and linked in the code below (on my actual sever) as well so Im not sure what the issue is.
push: {
android: {
senderId: '...',
apiKey: '...'
},
ios: {
pfx: '/file/path/to/XXX.p12',
passphrase: '', // optional password to your p12/PFX
bundleId: '',
production: false
}
}
My server is running on an Amazon EC2 instance as well.
Are you using AWS SNS to use push notification? If so, you can try setting this in your server code:
function sendPhoneNotification() {
AWS = require('aws-sdk');
AWS.config.update({
accessKeyId: '***',
secretAccessKey: '***',
region: 'ap-southeast-1'
});
var sns = new AWS.SNS();
var promise = new Parse.Promise();
sns.createPlatformEndpoint({
PlatformApplicationArn: '***',
Token: "***"
}, function (err, data) {
if (err) {
console.log("Error in endpoint" + err.stack);
//res.error("error stack 1: " + err.stack);
promise.reject(err.stack);
return promise;
}
var endpointArn = data.EndpointArn;
var payload = {
GCM: {
data: {
title: "YOUR TITLE",
message: "HELLO PUSH NOTIFICATION"
}
}
/* APNS: {
aps: {
alert: 'Hello World',
sound: 'default',
badge: 1
}
}*/
};
// payload.APNS = JSON.stringify(payload.APNS);
payload.GCM = JSON.stringify(payload.GCM);
payload = JSON.stringify(payload);
var result = sns.publish({
Message: payload,
MessageStructure: 'json',
TargetArn: endpointArn
}, function (err, data) {
if (err) {
promise.reject(err.stack);
return promise;
}
res.success("push sent " + JSON.stringify(data));
});
});
return promise;
}