I am receiving a reference error in AWS lambda - amazon-web-services

I am trying to learn to make a web app and I am trying to follow the tutorial provided by AWS but I am coming in to this issue in making a Lambda function.
{
"errorType": "ReferenceError",
"errorMessage": "exports is not defined in ES module scope",
"trace": [
"ReferenceError: exports is not defined in ES module scope",
" at file:///var/task/index.mjs:3:1",
" at ModuleJob.run (node:internal/modules/esm/module_job:193:25)",
" at async Promise.all (index 0)",
" at async ESMLoader.import (node:internal/modules/esm/loader:530:24)",
" at async _tryAwaitImport (file:///var/runtime/index.mjs:921:16)",
" at async _tryRequire (file:///var/runtime/index.mjs:970:86)",
" at async _loadUserApp (file:///var/runtime/index.mjs:994:16)",
" at async UserFunction.js.module.exports.load (file:///var/runtime/index.mjs:1035:21)",
" at async start (file:///var/runtime/index.mjs:1200:23)",
" at async file:///var/runtime/index.mjs:1206:1"
]
}
index.mjs
// Define handler function, the entry point to our code for the Lambda service
// We receive the object that triggers the function as a parameter
exports.handler = async (event) => {
// Extract values from event and format as strings
let name = JSON.stringify(`Hello from Lambda, ${event.firstName} ${event.lastName}`);
// Create a JSON object with our response and store it in a constant
const response = {
statusCode: 200,
body: name
};
// Return the response constant
return response;
};
JSON
{
"firstName":"Tyler",
"lastName":"Schnitzer"
}
It is suppose to be a simple hello world but I am confused why I can't get the event to work?
I am hoping someone can help explain this error and how to solve it, I tried looking through AWS Lambda trouble shooting page, but I still don't understand.

I had the same error. I deleted and recreated the lambda function with a runtime of Node.js 14.x, it works fine. The error was with Node.js 18.x, which is the default as of this writing.
I was following this tutorial, https://www.eventbox.dev/published/lesson/innovator-island/2-realtime/2-backend.html

Related

How do you pass query parameters to a GET endpoint

I have a simple Lambda function that for now returns the event. So when I test with this, I return event.body.url and event.body.wepbSupport. That works in the AWS Lambda test environment.
TEST
{
"body": {
"url": "https://someURL.com",
"webpSupport": true
}
}
RESPONSE
Test Event Name
test
Response
{
"url": "https://someURL.com",
"webpSupport": true
}
I have no idea how to pass this query string to the staging API Gateway staging URL. All the documentation from AWS shows an old interface that they've changed. I see add URL Query String Parameters in these instructions but don't see that anywhere in the new interface.
Cloudwatch logs show me this:
{
"errorType": "TypeError",
"errorMessage": "The \"url\" argument must be of type string. Received undefined",
"code": "ERR_INVALID_ARG_TYPE",
"stack": [
"TypeError [ERR_INVALID_ARG_TYPE]: The \"url\" argument must be of type string. Received undefined",
" at validateString (internal/validators.js:124:11)",
" at Url.parse (url.js:170:3)",
" at Object.urlParse [as parse] (url.js:157:13)",
" at dispatchHttpRequest (/var/task/node_modules/axios/lib/adapters/http.js:91:22)",
" at new Promise (<anonymous>)",
" at httpAdapter (/var/task/node_modules/axios/lib/adapters/http.js:46:10)",
" at dispatchRequest (/var/task/node_modules/axios/lib/core/dispatchRequest.js:52:10)",
" at async Promise.all (index 0)",
" at async Runtime.exports.handler (/var/task/index.js:4:28)"
]
}
After examining the event object I see that all GET query parameters are passed in event.queryStringParameters. Leaving this on the site in case anyone else stumbles across this question.

TestCafe works with SAM Local but not after SAM Deploy

I'm currently trying to set up an AWS Lambda (nodejs10.x) function that should execute a simple TestCafe test.
If I run my Lambda locally with sam local invoke --no-event it executes just fine:
2019-12-03T13:39:46.345Z 7b906b79-d7e5-1aa6-edb7-3e749d4e4b08
INFO hello world ✓ My first test 1 passed (1s)
2019-12-03T13:39:46.578Z 7b906b79-d7e5-1aa6-edb7-3e749d4e4b08
INFO Tests failed: 0
After I deployed it with sam build and sam deploy it stops working. It just throws the following error in AWS:
{
"errorType": "Runtime.UnhandledPromiseRejection",
"errorMessage": "Error: Page crashed!",
"trace": [
"Runtime.UnhandledPromiseRejection: Error: Page crashed!",
" at process.on (/var/runtime/index.js:37:15)",
" at process.emit (events.js:203:15)",
" at process.EventEmitter.emit (domain.js:448:20)",
" at emitPromiseRejectionWarnings (internal/process/promises.js:140:18)",
" at process._tickCallback (internal/process/next_tick.js:69:34)"
]
}
My lambda handler looks like this:
const createTestCafe = require("testcafe");
const chromium = require("chrome-aws-lambda");
let testcafe = null;
exports.lambdaHandler = async (event, context) => {
const executablePath = await chromium.executablePath;
await createTestCafe()
.then(tc => {
testcafe = tc;
const runner = testcafe.createRunner();
return runner
.src("sample-fixture.js")
.browsers(
"puppeteer-core:launch?arg=--no-sandbox&arg=--disable-gpu&arg=--disable-setuid-sandbox&path=" + executablePath
)
.run({
skipJsErrors: true,
selectorTimeout: 50000
});
})
.then(failedCount => {
console.log("Tests failed: " + failedCount);
testcafe.close();
});
return {
statusCode: 200
};
};
My sample-fixture.js looks like this:
fixture `Getting Started`
.page `http://devexpress.github.io/testcafe/example`;
test('My first test', async t => {
console.log('hello world');
});
I'm using the following dependencies:
"testcafe": "^1.7.0"
"chrome-aws-lambda": "^2.0.1"
"testcafe-browser-provider-puppeteer-core": "^1.1.0"
Has someone an idea why my Lambda functions works locally on my machine but not in AWS?
I cannot currently say anything precise based only on this information.
I suggest you try the following:
Check that packet deployed size is less then 50 Mb (https://github.com/puppeteer/puppeteer/blob/master/docs/troubleshooting.md#running-puppeteer-on-aws-lambda)
Check that testcafe-browser-provider-puppeteer-core can be run on the AWS Labmda
So I've been able to run testcafe in an AWS lambda. The key for me was to take advantage of Lambda Layers. (https://docs.aws.amazon.com/lambda/latest/dg/configuration-layers.html)
The issue with testcafe it that it's a huge package, both it and chrome-aws-lambda should be deployed in Layers, as you may exceed the bundle size limit.
Also, you may run into an issue with speed on the Lambda as testcafe compiles the files in babel. If your files are already compiled it may add additional unneeded time to your execution.
Hope this helps!

AWS API Gateway: Can't map thrown error from Lambda to Method Response using Integration Response

The issue
Using the Integration Response feature of AWS API Gateway, I can successfully handle errors thrown by Lambda. However, I'm having trouble mapping the Javascript error object to the mapping template. The error object looks like this.
{
"errorMessage": "Error: ABC123",
"errorType": "Error",
"stackTrace": [
"exports.handler (/var/task/index.js:9:11)"
]
}
Here's my Integration Response mapping for application/json
#set($errorMessage = $input.path('$.errorMessage'))
{
"message" : $errorMessage
}
What I've tried
Using this configuration, this is the entire response returned to the client: Unexpected 'E'. This is one string and is not contained in a JSON object.
This E that's referenced in the error is the first character from my thrown error message, which is used to match the Lambda Error Regex. I know this as I briefly changed the first letter to X and I got Unexpected 'X' as the response.
When I change the first line of my mapping template to this (mapping the entire object rather than attempting to just map the errorMessage property)
#set($errorMessage = $input.path('$'))
I get only the stack trace from the Javascript error object.
{
"message" : [
"exports.handler (/var/task/index.js:9:11)"
]
}
This would suggest that either the entire response object being returned to API Gateway is just the stackTrace property from the Javascript error. But to me, this doesn't make sense as something is picking up the errorMessage as thats where the Unexpected 'E' message is coming from.
Similarly, when I try and map the errorType property, I get the same error as it also starts with E. I can only successfully map the message property when I use the entire $ input object, or just the stackTrace property.
What am I doing wrong here?
Other relevant code
Here's the API Gateway Error Model. The message property is clearly marked as a string type yet it only works when I return an array. Note: this is the default code
{
"$schema" : "http://json-schema.org/draft-04/schema#",
"title" : "Error Schema",
"type" : "object",
"properties" : {
"message" : { "type" : "string" }
}
}
Here's the Lambda function code
exports.handler = async (event, context, callback) => {
throw new Error(Error: ABC123);
};
I've figured it out. The solution is to use $input.json() rather than $input.path()
Here's my new mapping template
{
"errorMessage" : $input.json('$.errorMessage')
}

AWS Lambda Function assistance

I just started with AWS and i am creating my first Lambda functions. The first one was success - no issues when creating and executing.
Now i am trying to create Lambda function (python 3 based) with couple parameters. When i perform test from the API Gateway i can see it executes ok. When i try to execute from browser i see the following error:
{
"errorMessage": "'foo2",
"errorType": "KeyError",
"stackTrace": [
" File \"/var/task/lambda_function.py\", line 6, in lambda_handler\n foo2 = event['foo2'];\n"
]
}
Here is the function and mapping templates:
import json
import sys
def lambda_handler(event, context):
foo1 = event['foo1'];
foo2 = event['foo2'];
foo3 = event['foo3'];
foo = "This is Test!";
# TODO implement
return {
'statusCode': 200,
'body': json.dumps(event)
}
Mapping template
#set($inputRoot = $input.path('$'))
{
"foo1": "$input.params('foo1')",
"foo2": "$input.params('foo2')",
"foo3": "$input.params('foo3')"
}
I really wonder why this is happening..
I'm not an API gateway wizard, but it looks like you are trying to assign the variable foo2 to a part of the event that doesn't exist when invoking the function from the Browser, when testing the event you might want to look at the structure of the event. It might help inside your Lambda function to add a json.dumps direct under the lambda_handler to try understand if there are missing parameters.

Aws Pass Value from Lambda Trigger to Step Function

When using a Lambda Function to trigger a Step Function, how do you get the output of the function that triggered it?
Ok, so if you want to pass an input to a Step Function execution (or, more exactly, your 'State Machine''s execution), you just need to set said input the input property when calling StartExecution (see AWS Documentation: Start Execution)
In your case, it would most likely be your lambda's last step before calling it's callback.
If it's a node js lambda, that's what it would look like
const AWS = require("aws-sdk");
const stepfunctions = new AWS.StepFunctions();
exports.myHandler = function(event, context, callback) {
... your function's code
const params = {
stateMachineArn: 'YOUR_STATE_MACHINE_ARN', /* required */
input: 'STRINGIFIED INPUT',
name: 'AN EXECUTION NAME (such as an uuid or whatever)'
};
stepfunctions.startExecution(params, function(err, data) {
if (err) callback(err); // an error occurred
else callback(null, "some success message"); // successful response
});
}
Alternatively, if your payload is too big, you could store the data in S3 or DynamoDB and pass the reference to it as your State Machine's execution's input.