I was trying to get the thing shadow of a resource of aws iot in lambda function but the given code is giving null value on success instead of a data. Please let me know where is the problem and what changes should i do to make it work fine. Thanks in advance.
var AWS=require('aws-sdk');
var iotdata = new AWS.IotData({endpoint: 'XXXXXXXXX.iot.us-east-1.amazonaws.com'});
var params = {
thingName: 'thing_name' /* required */
};
exports.handler=function(event,context){
payload1=new Buffer(event.payload);
console.log(payload1);
iotdata.getThingShadow(params, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else console.log(data); // successful response
context.succeed(data);
});
};
There are few places which need to be changed. Here is the new code:
getIotShadow: function (thingName) {
config.IOT_BROKER_ENDPOINT = "xxxxxxxxx.iot.us-east-1.amazonaws.com"; // also called the REST API endpoint
config.IOT_BROKER_REGION = "us-east-1"; // eu-west-1 corresponds to the Ireland Region. Use us-east-1 for the N. Virginia region
config.IOT_THING_NAME = thingName;
AWS.config.region = config.IOT_BROKER_REGION;
var iotData = new AWS.IotData({
endpoint: config.IOT_BROKER_ENDPOINT
});
var paramsGet = {
"thingName": config.IOT_THING_NAME /* required */
};
iotData.getThingShadow(paramsGet, function (err, data) {
if (err) {
console.log("Error : " + err, err.stack);
} else {
console.log(JSON.stringify(data));
}
});
}
Related
I am playing the aws mobilehub with react-native and I was hoping that it can speed up the backend hosting for me.
However, I cannot get its backend API working. After a long run with their docs, I pin down the problem between its lambda function and dynamodb service.
Any thoughts are greatly appreciated!
Problem#1
As the titled says: my aws lambda functions can request its dynamodb but has no response.
What went wrong here?
Or how can I get debug info from AWS dynamodb? (I gg and enabled Cloudtrial but it doesn't seem to have operation logs of the dynamodb too.)
Lambda side
Here I have the simplest node.js 6.10 codes:
const AWS = require('aws-sdk');
AWS.config.update({region: 'us-east-2'});
const dynamodb = new AWS.DynamoDB.DocumentClient();
exports.handler = function(event, context, callback) {
var responseCode = 200;
var requestBody, httpMethod, res;
console.log("request: " + JSON.stringify(event));
// Request Body
requestBody = event.body;
/*testing dynamodb with put*/
console.log("PUT begins");
let putItemParams2 = {
TableName: "xxxx-mobilehub-xxxx-Test",//tableName
Item: {businessId:'putItemParams2r3',test:'yooo', hmm:'hhhh'}
};
console.log("putItemParams2: ",putItemParams2);
dynamodb.put(putItemParams2, (err, data) => {
console.log("putItemParams2");
if (err) console.log("dynamodb err: ",err, err.stack); // an error occurred
else console.log("dynamodb data: ",data); // successful response
});
console.log("PUT end");
var response = {
statusCode: responseCode
//....
};
...
//comment out context.succeed here to avoid program termination before intended.
//console.log("response: " + JSON.stringify(response))
//context.succeed(response);
};
Logs
When the previouse codes are triggered, from AWS CloudWatch I can see logs:
START RequestId: 3d7c5f7f-1b98-11e8-ad00-93a6d10c8f4e Version: $LATEST
[timestamp] PUT begins
[timestamp] putItemParams2: { TableName: 'xxx-mobilehub-xxxx-Test',
Item: { businessId: 'putItemParams2r3', test: 'yooo', hmm: 'hhhh'}}
[timestamp] put end
END RequestId: 3d7c5f7f-1b98-11e8-ad00-93a6d10c8f4e
So no err, no data, no response. I checked my dynamodb and there is nothing insert.
Extra info
condition#1: this dynamodb table has public access since I want to rule out the auth problem.
condition#2: I ensure that my lambda function has access to these tables. e.g. arn:aws:dynamodb::xxxx:table/xxxx-mobilehub-xxxx- allow everything
condition#3: I build myself a simple node.js to execute the (aws-sdk)and this server works perfectly fine with the same code..
I am able to "get" &"put" items int & out from my dynamodb table.
Problem#2
my react-native code use 'aws-amplify-react-native'. Which the API.put is fine and the lambda function is at least receiving the api call (from problem#1).
However, API.get returns me 403 error, and the lambda function doesn't even has log for this operation..
async function getBusiness(){
const path = "/Test";
const api = "TestCRUD";
let queryGetBusiness = {body: {userId: "hmmm"}};
try {
let apiResponse = await API.get(api, path, queryGetBusiness)//.then((data)=>{console.log(data)});
let apiResponseJson = await JSON.stringify(apiResponse);
console.log("response from saving Business: " + apiResponseJson);
}
catch (e) {console.log(e);}
}
P.S.(AWS could do much better with this mobilehub.. their documentation is lacking details and awsmobile cloud-api invoke has some problems I guess.)
const AWS = require('aws-sdk');
AWS.config.update({ region: 'us-east-2' });
const dynamodb = new AWS.DynamoDB.DocumentClient();
exports.handler = function (event, context, callback) {
var responseCode = 200;
var requestBody, httpMethod, res;
console.log("request: " + JSON.stringify(event));
// Request Body
requestBody = event.body;
/*testing dynamodb with put*/
console.log("PUT begins");
let putItemParams2 = {
TableName: "xxxx-mobilehub-xxxx-Test",//tableName
Item: { businessId: 'putItemParams2r3', test: 'yooo', hmm: 'hhhh' }
};
console.log("putItemParams2: ", putItemParams2);
dynamodb.put(putItemParams2, (err, data) => {
console.log("putItemParams2");
if (err) console.log("dynamodb err: ", err, err.stack); // an error occurred
else {
console.log("dynamodb data: ", data);
context.succeed(response);
}
// Call these here
console.log("PUT end");
});
//console.log("response: " + JSON.stringify(response))
};
Make sure you call context.succeed inside the callback function. Like above.
You can also just use the third argument to handler function - callback instead of context.succeed like callback(null, response);
I am playing with AWS Lambda along with Twilio. I have a Lambda function that integrates Lex with Twilio. I also have another Lambda function that does the the validations for my LexBot. Both work fine separately. However, I'm trying to put them together so whenever my LexBot integrates with Twilio, it also calls my validations in the same Lambda function.
Any ideas? Thank you.
Here is the Lambda that integrates Lex with Twilio:
var twilio = require('twilio');
var qs = require('qs');
var AWS = require('aws-sdk');
exports.handler = (event, context, callback) => {
try {
var twilioSMS = qs.parse(event["body-json"]);
// ************************
// validate and filter bad/empty messages
// ************************
if(!twilioSMS.hasOwnProperty('Body')){
var error = new Error("Cannot process message without a Body.");
callback(error);
}
else {
// Message is valid so now we prepare to pass it along to the Lex API.
AWS.config.region = 'us-east-1';
var lexruntime = new AWS.LexRuntime();
var userNumber = twilioSMS.From.replace('+', '');
var params = {
botAlias: process.env.BOT_ALIAS,
botName: process.env.BOT_NAME,
inputText: twilioSMS.Body,
userId: userNumber,
sessionAttributes: {
}
};
lexruntime.postText(params, function(err, data) {
var twimlResponse = new twilio.TwimlResponse();
if (err) {
console.log(err, err.stack); // an error occurred
twimlResponse.message('Sorry, we ran into a problem at our end.');
callback(err, twimlResponse.toString());
} else {
console.log(data); // got something back from Amazon Lex
twimlResponse.message(data.message);
callback(null, twimlResponse.toString());
}
});
}
} catch(e) {
console.log(e);
callback(e);
}
};
And here is my Lambda with the validations:
exports.handler = (event, context, callback) => {
// TODO implement
var numberType =event.currentIntent.slots.number,
response = "is not valid. Try 'One' or 'Two'." ;
if(numberType === "one" ) {
response = "Call: 111 111 1111 "
}
else if(numberType === "two") {
response = "Call: 222 222 2222"
}
callback(null, {
"dialogAction": {
"type": "Close",
"fulfillmentState": "Fulfilled",
"message": {
"contentType": "PlainText",
"content": "Your option: " + event.currentIntent.slots.number + ": " + response
}
}
});
};
Step functions would be your friend. Please have a look at below links,
https://aws.amazon.com/step-functions/
https://cloudacademy.com/blog/aws-step-functions-a-serverless-orchestrator/
I realized didn't need to write a Lambda function to connect Lex with Twilio. All I had to do was go to 'Channels' under my LexBot Console and integrate manually my bot with my Twilio account.
I want to merge data from two tables and then send the result as the response.
I'm new to nodejs and lambda and I'm unable to figure out how I can merge json data from both scan calls and send it as the response.
If I uncomment the callback then response for only one table is sent.
My code is below, can someone please help in completing it
'use strict';
const AWS = require("aws-sdk");
const dynamodb = new AWS.DynamoDB();
const docClient = new AWS.DynamoDB.DocumentClient();
exports.handler = function(event, ctx, callback) {
var params= {
TableName:'x',
FilterExpression:'SessionId = :SessionId',
ExpressionAttributeValues:{ ":SessionId" : 'ca47a131'},
};
var params1= {
TableName:'y',
FilterExpression:'sessionid = :SessionId',
ExpressionAttributeValues:{ ":SessionId" : 'ca47a131'},
};
docClient.scan(params, onScan);
docClient.scan(params1, onScan1);
function onScan(err, data){
if(err){
callback(err, null);
}else{
//callback(null, data);
}
}
function onScan1(err, data){
if(err){
callback(err, null);
}else{
//callback(null, data);
}
}
}
You can use the following modification to the code so that you can send the response in a single callback.
'use strict';
const AWS = require("aws-sdk");
const dynamodb = new AWS.DynamoDB();
const docClient = new AWS.DynamoDB.DocumentClient();
exports.handler = function(event, ctx, callback) {
var params= {
TableName:'x',
FilterExpression:'SessionId = :SessionId',
ExpressionAttributeValues:{ ":SessionId" : 'ca47a131'},
};
var params1= {
TableName:'y',
FilterExpression:'sessionid = :SessionId',
ExpressionAttributeValues:{ ":SessionId" : 'ca47a131'},
};
docClient.scan(params, onScan);
docClient.scan(params1, onScan1);
var firstResultData = false;
function runAfterBothCallbacks(data){
if(!firstResultData){
firstResultData = data;
}else{
// Combine firstResultData with data and return in the callback
callback(null,{ dataX: firstResultData, dataY: data });
// Note: The order of scan and scan1 result coming cannot be guaranteed so, dataX can be the results of scan or scan1. If you can identify the result based on the scan, either pass it as another parameter to the runAfterBothCallbacks method or identify the scan based on data result (If possible).
}
}
function onScan(err, data){
if(err){
callback(err, null);
}else{
runAfterBothCallbacks(data);
}
}
function onScan1(err, data){
if(err){
callback(err, null);
}else{
runAfterBothCallbacks(data);
}
}
}
Welcome to JavaScript asynchronous callbacks (aka callback hell).
Fortunately, the AWS SDK supports promises so you can use Promise.all() to wait for multiple promises to be resolved. When that happens, merge the JSON results and return the merged result via the Lambda function's callback() method.
I have a Lambda function that imports a node package with common functions. Lambda 1 puts messages into SQS, Lambda 2 does error logging. One of the shared functions invokes Lambda 2, but there's an error on that second invocation.
Lambda 1:
exports.handler = function (event, context) {
var pnmacCommon = require('./pnmacCommon.js'); //loading node package
try {
// this part omitted for space
var aws = require('aws-sdk');
var sqs = new aws.SQS({ region : 'us-west-2' });
var params = {
MessageBody: JSON.stringify(event),
QueueUrl: '[url]'
};
sqs.sendMessage(params, function(err,data){
if(err) {
console.log('error:',"FAIL Send Message: " + err);
context.done(err, "ERROR Put SQS"); // ERROR with message
pnmacCommon.SvtLogErrorToElmah(application, "FAIL Send Message: " + err, context);
}else{
console.log('Message Sent:', queueUrl);
console.log('data:',data.MessageId);
context.done(null,''); // SUCCESS
}
}
});
}
catch (error) {
pnmacCommon.SvtLogErrorToElmah(application, 'SVTMessageBus_Client' + error, context);
context.done(error, "ERROR put SQS");
}
pnmacCommon.js:
var SvtLogErrorToElmah = function (application, error, context) {
console.log("SvtLogErrorToElmah=" + JSON.stringify(error, null, 2));
// this part omitted for space
var aws = require('aws-sdk');
var lambda = new aws.Lambda({region: 'us-west-2' });
lambda.invoke({
FunctionName: "SVTExceptionLogger",
Payload: JSON.stringify(message, null, 2)
}, function (error2, data) {
if (error2) {
context.fail(error2);
} else {
context.fail(error);
});
context.done(null, message);
}
module.exports.SvtLogErrorToElmah = SvtLogErrorToElmah;
Looking in Cloudwatch, I can see that the SvtLogErrorToElmah function gets called, but it fails when it tries to invoke the second Lambda. The error message is TypeError: lambda.invoke is not a function.
Any ideas? Thank you in advance.
It turns out this was an issue with variable scoping. In the shared function, we reuse the variable name aws. Once I changed this to a different name, the problem went away.
I just got the same error that you had, and for me the update of the aws-sdk version resolved the issue.
UPDATED the package.json [aws-sdk version]
old (with 'TypeError: lambda.invoke is not a function')
"dependencies": {
"aws-sdk": "^2.1.17"
}
to (fixed the error)
"dependencies": {
"aws-sdk": "^2.18.0"
}
I'm trying to do something relatively simple and am running into a "server ...-a.mongolab.com:36648 sockets closed" error all of a sudden every time I try to do an "insert".
Reads seem to work without error, but inserts seem to get an error every time and I'm not sure if it's my code (which recently underwent minor changes), or a reliability problem with the free server I'm using at MongoLab (which recently showed itself to be down for a few minutes).
Oddly enough, the record itself seems to save okay, I just get the error back!
Can anyone see an issue with my code, or could this be something else?
var mongoClient = require('mongodb').MongoClient;
var http = require('http');
var connectionString = "...";
var pictureWallsCollectionName = 'PictureWalls';
//this is what barfs. see *** details
exports.saveWall = function (req, res) {
//reformat
var toSave = {
_id: req.body.wallId,
pictures: req.body.pictures
};
var status;
mongoClient.connect(connectionString, function (err, db) {
if (err) { return console.error(err); }
var collection = db.collection(pictureWallsCollectionName);
//*** no err yet... ***
collection.insert(
toSave,
function (error, response) {
//*********************
//*** err here! ******
//*********************
db.close();
if (error) {
console.error(error);
//bad
status = 500;
}
else {
console.log('Inserted into the ' + collection_name + ' collection');
//good
status = 200;
}
});
response.status(status).end(http.STATUS_CODES[status]);
});
}
//this seems to work pretty reliably. including it just in case it's relevant
exports.findByWallId = function (req, res) {
var id = req.params.id;
console.log('Retrieving wall: ' + id);
mongoClient.connect(connectionString, function (err, db) {
if (err) { return console.dir(err); }
var collection = db.collection(pictureWallsCollectionName);
collection.findOne(
{ _id: id },
function (err, item) {
db.close();
if (err) {
console.error(err);
//something bad happened
var status = 500;
res.status(status).end(http.STATUS_CODES[status]);
}
else {
console.log('Found wall with ID ' + id);
//reformat and send back in the response
res.send({
wallId: item._id,
pictures: item.pictures
});
}
}
);
});
};
EDIT: Part of my original issue was duplicate parameter names. See the linked question for detail.
ORIGINAL RESPONSE:
The issue ended up being that I was calling:
res.status(status).end(http.STATUS_CODES[status]);
...before the async insert was finished, so it barfed.
However, I'm not exactly sure how to issue the response in this case. See my new question here:
How Do I Properly Issue Response To Post When Waiting For Async Method To Complete?