I am very new to AWS Lambda and Node.js, so apologies for the elementary question. I have two JS files in my Lambda project's root directory:
index.js
engageMessage(); //For testing purposes - throws error
exports.handler = async (event) => {
// TODO implement
const response = {
statusCode: 200,
body: JSON.stringify('This is index'),
};
return response;
};
messenger.js
function engageMessage() {
console.log("Messenger, checking in!");
};
How do I call engageMessage() from my index.js file? Each time I try, I get a "TypeError: engageMessage is not a function" message, and am unsure of how to properly reference/import/require messenger.js.
In messenger.js you need to export your function
module.exports = { engageMessage }
Then require it in your index.js
const { engageMessage } = require("./messenger.js")
I am using the #aws-sdk/client-lambda npm package for invoking lambdas. I have two Lambdas. Lambda A & Lambda B. Lambda A is trying to invoke Lambda B.
Lambda A invokes Lambda B by running the following code:
const { LambdaClient, InvokeCommand } = require('#aws-sdk/client-lambda');
module.exports = {
getGitHubToken: async () => {
const client = new LambdaClient({ region: process.env.REGION });
const params = {
FunctionName: process.env.GITHUB_TOKEN_FUNCTION,
LogType: 'Tail',
Payload: '',
};
const command = new InvokeCommand(params);
try {
const { Payload } = await client.send(command);
console.log(Payload);
return Payload;
} catch (error) {
console.error(error.message);
throw error;
}
},
};
The expected response from Lambda B should look like this:
{
statusCode: 200,
body: JSON.stringify({
token: '123',
}),
};
However, Payload looks to be returning this from the line console.log(Payload);:
I looked on the AWS SDK Website and it looks like Payload returns a Uint8Array. I guess this is because it's from a promise?
I have tried doing Payload.toString() however that comes back as simply a string of the values in the Unit8Array. Example being:
2021-04-13T14:32:04.874Z worker:success Payload: 123,34,115,116,97,116,117,115,67,111,100,101,34,58,50,48,48,44,34,98,111,100,121,34,58,34,123,92,34,116,111,107,101,110,92,34,58,92,34,103,104,115,95,111,114,101,51,65,109,99,122,86,85,74,122,66,52,90,68,104,57,122,122,85,118,119,52,51,50,111,67,71,48,50,75,121,79,69,72,92,34,125,34,125
My Question:
How do I resolve data from Unit8Array to the data I was expecting from the Lambda response? Which is a JSON Object?
I have confirmed the requested Lambda (Lambda B in this case) is returning the data correctly by going to CloudWatch. Thanks.
Okay, I found a way to get this working.
You have to specify a text encoder:
const asciiDecoder = new TextDecoder('ascii');
Then decode it so it looks like this:
const data = asciiDecoder.decode(Payload);
I have logged an issue on their repository asking why this isn't included in the module. I will post an update on any movement on this.
Here is my AWS Lambda function. However, when running it, I get Cannot read property '0' of undefined.
const AWS = require('aws-sdk');
const SES = new AWS.SES();
const FROM_EMAIL_ADDRESS = process.env.FROM_EMAIL_ADDRESS;
const TO_EMAIL_ADDRESS = process.env.TO_EMAIL_ADDRESS;
function sendEmailToMe(formData) {
const emailParams = {
Source: FROM_EMAIL_ADDRESS,
ReplyToAddresses: ['keshijemi478#gmail.com'],
Destination: {
ToAddresses: [TO_EMAIL_ADDRESS],
},
Message: {
Body: {
Text: {
Charset: 'UTF-8',
Data: `Thanks for subscribe: ${formData.message}\n\n Name: ${formData.name}\n Email: ${formData.email}\n I will reply as soon as possible`,
},
},
Subject: {
Charset: 'UTF-8',
Data: 'New message from your_site.com',
},
},
};
console.log(emailParams);
const promise = SES.sendEmail(emailParams).promise();
console.log(promise);
return promise;
}
exports.handler = async(event) => {
console.log('SendEmail called');
const dynamodb = event.Records[0].dynamodb;
console.log(dynamodb);
const formData = {
name : dynamodb.NewImage.name.S,
message : dynamodb.NewImage.message.S,
email : dynamodb.NewImage.email.S
};
console.log(formData);
return sendEmailToMe(formData).then(data => {
console.log(data);
}).catch(error => {
console.log(error);
});
};
It appears that your code is an AWS Lambda function.
When a Lambda function is called, information is passed to the function via the event parameter. The information passed via event varies depending upon how the function was triggered. For example, if the function is triggered by an Amazon S3 Event, then S3 provides information in the event parameter that describes the object that caused the event to be triggered.
If, however, you trigger this event 'manually', then Amazon S3 is not involved and the event parameter only contains the information that you provided when you invoked the function.
If you are testing the function in the AWS Lambda management console, you can supply an event via the "Configure Test" option. The event provided in this configuration will then be passed to the function being tested.
I have this code in node.js (nodejs10.x) running in AWS Lambda.
module.exports.register = (event, context, callback) => {
// Body es un json por lo que hay que deserializarlo
let body = JSON.parse(event.body);
let rules = {
'name': 'required|min:3',
'family_name': 'required|min:3',
'email': 'required|email',
'curp': 'required|size:18',
'modules': 'required',
'password': 'required'
};
let validation = new validator(body, rules);
// If errors this validation exits using the callback
if(validation.fails()){
console.log(validation.errors.all())
const response = {
statusCode: 422,
body: JSON.stringify(validation.errors.all())
};
callback(null, response);
}
// just for testing
const isModulesValid = false;
if(!isModulesValid){
console.log('Modules validation failed. ')
const response = {
statusCode: 422,
body: JSON.stringify({'modules': 'Invalid modules string. '})
};
callback(null, response);
// However this is not working
}
// and even if there is an error this code is executed
console.log('XXXX');
I am testing it locally with a code like this.
// Callback
let callback = function(err, result) {
if (err)
console.log(err);
if (result)
console.log(result);
// Terminate execution once done
process.exit(0);
}
// lambda.generateToken(event, context, callback);
lambda.register(event, context, callback);
Locally if isModulesValid = false the code exits and the console.log('XXXX') is not executed. However when running it in AWS Lambda, even if the validation fails the code continues to run and the console.log() is executed.
I cannot figure out whats going on. Help please?
Locally you are using the callback which has process.exit(0); which is making the process finish and hence the next line is not executing. Callback doesn't mean that the code afterwards wouldn't be executed. the code flow continues after that as well. It all depends on what you have in your callback.
This piece of code solved the problem:
if(!isModulesValid){
console.log('Modules validation failed. ')
const response = {
statusCode: 422,
body: JSON.stringify({'modules': 'Invalid modules string. '})
};
// Return callback explcitly
return callback(null, response);
}
Apparently it has to do with how AWS Lambda handles the task queue. I found a good explanation here: https://blog.danillouz.dev/aws-lambda-and-the-nodejs-event-loop/
I am using AWS Lambda and I have 2 functions within my handler.js file. I want to call the one function (getClient) within the other function. The problem I am having is that the first function (getClient) needs query string parameters and I don't know how to attach that when calling the function.
I have tried changing the event object that is sent to the function and adding the query string parameter as a json but that doesn't work.
let json = JSON.parse(event.body);
event = {
emailAddress: json.clientEmailAddress
}
var client = this.getClient(event);
console.log(client)
I get the error that queryStringParameter is undefined.
errorType": "TypeError",
"errorMessage": "Cannot read property 'queryStringParameters' of undefined",
To invoke an AWS Lambda function from another function, I would suggest to use the AWS SDK and use the invoke API call.
https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/Lambda.html#invoke-property
Invoke is taking an PayLoad parameter that can contain any object.
For example :
try {
const lambdaParams = {
FunctionName: 'my-lambda',
// RequestResponse is important here. Without it we won't get the result Payload
InvocationType: 'RequestResponse',
LogType: 'Tail', // other option is 'None'
Payload: queryStringParameters
};
const lambda = new AWS.Lambda({region: 'eu-west-1', apiVersion: '2015-03-31'});
const const lambdaResult = await lambda.invoke(JSON.stringify(lambdaParams.Payload)).promise();
logger.debug(`Lambda returned : ${lambdaResult.Payload}`);
const resultObject = JSON.parse(lambdaResult.Payload)
} catch (e) {
console.error(e);
}