1

Working in the Lambda console, using Node v.18 runtime, and am getting really confused while trying to do some really simple beginner tasks. Specifically, I want to write a Lambda that will be called from API Gateway. This called Lambda will contain / call other lambdas.

Any / all advice is welcome.

Here's some code:

index.mjs:

   import AWS from 'aws-sdk';     // <== ERROR HERE
    
    export const handler = async (event) => {
        const lambda = new AWS.Lambda();
    
        try {
            const fetchFunction = // <== ARN for lambda here. We don't even get this far.
        // ... more code to do stuff follows

When I test the Lambda function, it returns an error. Here is the part of the error message that I can't sort out:

  "errorMessage": "Cannot find package 'aws-sdk' imported from /var/task/index.mjs\nDid you mean to import aws-sdk/lib/aws.js?",
  "trace": [
    "Error [ERR_MODULE_NOT_FOUND]: Cannot find package 'aws-sdk' imported from /var/task/index.mjs",
    "Did you mean to import aws-sdk/lib/aws.js?",

I've already researched a solution, but the more information I find, the more overwhelming it becomes.

Can anyone suggest a simple work-around / solution? I'm guessing this is really simple but I'm just not seeing a path to a solution.

Thanks in advance, m

mattBurnett
  • 94
  • 2
  • 9
  • It seems like your question should be "how to import the AWS SDK in a Lambda function" not "how to call one Lambda from another" since you are stuck on the import statement and haven't even gotten into the rest of the code yet. – Mark B May 24 '23 at 14:29
  • Fair enough. I've changed the question to reflect this. – mattBurnett May 24 '23 at 14:33
  • It depends on what version of NodeJS you are using, which affects what version of the AWS SDK is being included. But you should try replacing the import with `const AWS = require('aws-sdk')`. – Mark B May 24 '23 at 14:38
  • I'm using Node v.18.x – mattBurnett May 24 '23 at 14:40
  • OK? did you try my suggestion? – Mark B May 24 '23 at 14:42
  • Unfortunately that doesn't work with Node 18. Here is the error: "errorMessage": "require is not defined in ES module scope, you can use import instead", "trace": [ "ReferenceError: require is not defined in ES module scope, you can use import instead", – mattBurnett May 24 '23 at 15:28
  • Please read: https://aws.amazon.com/blogs/compute/node-js-18-x-runtime-now-available-in-aws-lambda/ – Mark B May 24 '23 at 15:33

2 Answers2

3

You're importing the v2 SDK. The node 18 lambda runtime only supports the v3 SDK.

May 2023 Lambda runtimeshttps://docs.aws.amazon.com/lambda/latest/dg/lambda-runtimes.html

You'll need to update your imports.

import { LambdaClient, InvokeCommand } from '@aws-sdk/client-lambda';

You can see more of the syntax in the guide. https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/preview/client/lambda/command/InvokeCommand/

If you're looking for more examples to get you started, I would suggest the Code Library. It has a good collection of examples in V3.

Corey
  • 463
  • 3
  • 12
  • 1
    Thanks! I managed to already stumble my way through to a solution, and your suggestions confirm the approach I followed. Also, the linked resources are new to me, and helpful. Thanks again! – mattBurnett May 24 '23 at 16:54
0

Just in case this helps future people, here is a dump of Lambda functions's code. It may not be structured perfectly, but it shows basic approach of what to do, to use JS SDK v.3 / Node v.18 on AWS and invoke "sub Lambdas":

Here is some code:

// Needs lambda execute IAM permission for each lambda, also.

import { LambdaClient, InvokeCommand } from "@aws-sdk/client-lambda";
const asciiDecoder = new TextDecoder('utf-8');

export const handler = async (event) => {
    const client = new LambdaClient();

    // https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-lambda/classes/invokecommand.html
    const fetchParams = {
        FunctionName: 'arn:aws:lambda:eu-north-1:880299674189:function:pv-estimate_fetchEstimate', // required
        // InvocationType: "Event" || "RequestResponse" || "DryRun",
        InvocationType: "RequestResponse",
        LogType: "Tail",
        // ClientContext: "STRING_VALUE",
        // Payload: "",
        // Qualifier: "STRING_VALUE",
    };


    const fetchCommand = new InvokeCommand(fetchParams);

    try {
        let retVal

        let response = await client.send(fetchCommand);
        // Payload comes back as array. Decode array and parse as json before returning data
        const estimate = JSON.parse(asciiDecoder.decode(response.Payload));

        const transformParams = {
            FunctionName: 'arn:aws:lambda:eu-north-1:880299674189:function:transformRecord', // required
            InvocationType: "RequestResponse",
            LogType: "Tail",
            Payload: JSON.stringify(estimate)
        };
        const transformCommand = new InvokeCommand(transformParams);
        response = await client.send(transformCommand);
        retVal = JSON.parse(asciiDecoder.decode(response.Payload));

        // API Gateway is picky about return payload format. https://stackoverflow.com/a/43718963/16824901
        return {
            statusCode: 200,
            headers: {
                "Access-Control-Allow-Origin": "*", // Required for CORS support to work
                "Access-Control-Allow-Credentials": true // Required for cookies, authorization headers with HTTPS
            },
            body: JSON.stringify(retVal),
        }

    }
    catch (error) {
        console.error('Error invoking Lambda function:', error);
        return {
            statusCode: 500,
            body: 'Error invoking Lambda function'
        };
    }
};
mattBurnett
  • 94
  • 2
  • 9