3

How can I invoke a lambda function using Javascript (TypeScript) aws-sdk v3?

I use the following code which does not seems to work:

// the payload (input) to the "my-lambda-func" is a JSON as follows:
const input = {
    name: 'fake-name',
    serial: 'fake-serial',
    userId: 'fake-user-id'
};

// Payload of InvokeCommandInput is of type Uint8Array
const params: InvokeCommandInput = {
    FunctionName: 'my-lambda-func-name',
    InvocationType: 'RequestResponse',
    LogType: 'Tail',
    Payload: input as unknown as Uint8Array, // <---- payload is of type Uint8Array
  };
  
  console.log('params: ', params); // <---- so far so good.
  const result = await lambda.invoke(params);
  console.log('result: ', result); // <---- it never gets to this line for some reason.

I see this error message in CloudWatch, not sure if it is relevant to my issue thought:

The first argument must be of type string or an instance of Buffer, ArrayBuffer, or Array or an Array-like Object. Received an instance of Object

Question:

Is the above code to invoke a lambda function correct? or are there any better ways?

A-Sharabiani
  • 17,750
  • 17
  • 113
  • 128
  • Are you running this code inside Lambda (to invoke a different Lambda)? If so, did the Lambda function time out? Also, do you have an exception handler that logs an error? – jarmod Oct 22 '21 at 15:23
  • 1
    [How do I ask a good question?](https://stackoverflow.com/help/how-to-ask): _"**Describe the problem**. "does not seems to work" isn't descriptive enough to help people understand your problem. Instead, tell other readers what the expected behavior should be. Tell other readers what the exact wording of the error message is, and which line of code is producing it. **Use a brief but descriptive summary of your problem as the title of your question**."_ – Andreas Oct 22 '21 at 15:24
  • @jarmod yes I'm invoking it from a different lambda, it does not timeout, I'm updating the question with the error message. thanks – A-Sharabiani Oct 22 '21 at 15:35
  • 1
    I presume you should send a JSON string via `JSON.stringify(input)`, not the object itself. – jarmod Oct 22 '21 at 15:42
  • @jarmod yea I think you're right. I did that and also I had to add `// @ts-ignore` cause TypeScript was complaining about: `Payload: JSON.stringify(input)` – A-Sharabiani Oct 22 '21 at 15:48
  • I believe this will work with TS: `Buffer.from(JSON.stringify(fnPayload))` – cyberwombat Mar 03 '22 at 18:12

2 Answers2

6

It looks like your call to lambda.invoke() is throwing a TypeError because the payload that you are passing to it is an object when it needs to be a Uint8Array buffer.

You can modify your code as follows to pass the payload:

// import { fromUtf8 } from "@aws-sdk/util-utf8-node";

const { fromUtf8 } = require("@aws-sdk/util-utf8-node");

// the payload (input) to the "my-lambda-func" is a JSON as follows:
const input = {
  name: 'fake-name',
  serial: 'fake-serial',
  userId: 'fake-user-id'
};

// Payload of InvokeCommandInput is of type Uint8Array
const params: InvokeCommandInput = {
  FunctionName: 'my-lambda-func-name',
  InvocationType: 'RequestResponse',
  LogType: 'Tail',
  Payload: fromUtf8(JSON.stringify(input)),
};
jarmod
  • 71,565
  • 16
  • 115
  • 122
5

As an alternative to the example above, you can avoid using an additional AWS library and use built-in Node function instead Buffer.from.

First import what you need:

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

Then define your function

export class LambdaService {    
    async invokeFunction(name: string): Promise<void> {
        try {
            const payload = { name: name };

            const input: InvokeCommandInput = {
                FunctionName: "my-lambda-func-name", 
                InvocationType: "Event", 
                Payload: Buffer.from(JSON.stringify(payload), "utf8"),
            };
        
            const command = new InvokeCommand(input);

            const res : InvokeCommandOutput = await lambdaClient.send(command);
        } catch (e) {
            logger.error("error triggering function", e as Error);
        }
    }
}

Then call it with:

const lambdaService = new LambdaService();
await lambdaService.invokeFunction("name");

If you miss the await, it is possible the function will start executing but never reach the last line.

  • There's a known issue with "util-utf8" missing from the embedded Lambda runtime with Node v18 (https://github.com/aws/aws-sdk-js-v3/issues/4401). Using Buffer allowed me not to have to bundle in that one AWS SDK module. – Ryan Bosinger May 09 '23 at 23:36