0
votes

I'm trying to push a record from the AWS Lambda function to the AWS DynamoDB. I can successfully push a record from my pc using AWS API but when I deploy the code to AWS I'm stuck.

Here's the example code that can successfully push a record from my PC:

const AWS = require("aws-sdk");
AWS.config.update({
  region: "eu-west-1",
  endpoint: "https://dynamodb.eu-west-1.amazonaws.com"
});
const docClient = new AWS.DynamoDB.DocumentClient();

const params = {
  TableName: "hello-world-bot",
  Item: {
    timestamp: Date.now(),
    chat_id: 123,
    text: 'text',
  },
};

console.log("Adding a new item...");
docClient.put(params, function(err, data) {
    if (err) {
        console.error("Unable to add item. Error JSON:", JSON.stringify(err, null, 2));
    } else {
        console.log("Added item:", JSON.stringify(data, null, 2));
    }
});

And the result in DynamoDB: Screenshot from DynamoDB console

And here's the code I'm trying to deploy to Lambda:

const AWS = require("aws-sdk");
AWS.config.update({
  region: "eu-west-1",
  endpoint: "https://dynamodb.eu-west-1.amazonaws.com",
});
const docClient = new AWS.DynamoDB.DocumentClient();

module.exports.helloworld = (event) => {
  const params = {
    TableName: "hello-world-bot",
    Item: {
      timestamp: Date.now(),
      chat_id: 123,
      text: "text",
    },
  };

  console.log("Adding a new item...");
  docClient.put(params, function (err, data) {
    if (err) {
      console.error(
        "Unable to add item. Error JSON:",
        JSON.stringify(err, null, 2)
      );
    } else {
      console.log("Added item:", JSON.stringify(data, null, 2));
    }
  });
  return { statusCode: 200 };
};

And the trouble is that there are no any records in DynamoDB when Lambda function runs. Here are logs from CloudWatch when I pull Lambda external API and try to run the function:

START RequestId: d9e171c2-a763-4df1-9ec3-06d79eb68a1e Version: $LATEST
2021-08-13T06:03:01.974Z    d9e171c2-a763-4df1-9ec3-06d79eb68a1e    INFO    Adding a new item...
END RequestId: d9e171c2-a763-4df1-9ec3-06d79eb68a1e
REPORT RequestId: d9e171c2-a763-4df1-9ec3-06d79eb68a1e  Duration: 45.04 ms  Billed Duration: 46 ms  Memory Size: 1024 MB    Max Memory Used: 88 MB  Init Duration: 524.54 ms

As you can see there are no any errors saying anything about permissions or else. These are the user permissions whose credentials are used with this function in Lambda:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "dynamodb:BatchGetItem",
                "dynamodb:GetItem",
                "dynamodb:Query",
                "dynamodb:Scan",
                "dynamodb:BatchWriteItem",
                "dynamodb:PutItem",
                "dynamodb:UpdateItem"
            ],
            "Resource": "arn:aws:dynamodb:eu-west-1:120400915578:table/hello-world-bot"
        }
    ]
}
2
Try not explicitly setting the DynamoDB endpoint (https://dynamodb.eu-west-1.amazonaws.com). You should never need to do this except if you run a local DynamoDB mock. This might already be the problem.Jens

2 Answers

0
votes

As I've pointed out in the comments of the other answer, their return statements do not seem entirely correct. I would prefer to use async-await syntax for promises which are supported by lambda and the AWS SDK out of the box.

This would change your code to look like the following:

const AWS = require("aws-sdk");
const docClient = new AWS.DynamoDB.DocumentClient();

module.exports.helloworld = async (event) => {
  const params = {
    TableName: "hello-world-bot",
    Item: {
      timestamp: Date.now(),
      chat_id: 123,
      text: "text",
    },
  };

  console.log("Adding a new item...");
  try {
    await docClient.put(params).promise();
    return { statusCode: 200 };
  } catch (err) {
    console.error("Unable to add item. Error JSON:",
        JSON.stringify(err, null, 2));
    return { statusCode: 500 };
  }
};

PS: As pointed out in the comments as well, you don't need to set the endpoint for DynamoDB if you're using the default endpoint. And since you're running the function as a Lambda an AWS_REGION environment variable will be set automatically, so you also don't need to configure this yourself (unless you want to access a DynamoDB table in another region).

0
votes

your return { statusCode: 200 }; ends the lambda invocation, but it does not wait for the put request to finish. It probably don't even wait for it to start, actually.

Either return your main function from the put callback, or use promises. Example with promise:

module.exports.helloworld = async (event) => { // <- use async
  const params = {
    TableName: "hello-world-bot",
    Item: {
      timestamp: Date.now(),
      chat_id: 123,
      text: "text",
    },
  }

  console.log("Adding a new item...")
  // Create a promise and return it
  return docClient
    .put(params)
    .promise()
    .then(() => {
      console.log("success")
      return {statusCode: 200}
    })
    .catch(e => {
      console.log("error: ", e)
      return {statusCode: 500}
    })
}

Also, as pointed out by @jens in the comments, explicitely setting a dynamodb endpoint is not required