1
votes

I am trying to use AWS mobile backend (using lambda function) to insert into dynamoDB (also configured at the mobile backend) but with no success so far.

The relevant code:

'use strict';
console.log("Loading function");

const AWS = require('aws-sdk');
const docClient = new AWS.DynamoDB.DocumentClient({region:process.env.MOBILE_HUB_PROJECT_REGION});



exports.handler = function(event, context, callback) {
    var responseCode = 200;
    var requestBody, pathParams, queryStringParams, headerParams, stage,
    stageVariables, cognitoIdentityId, httpMethod, sourceIp, userAgent,
    requestId, resourcePath;
    console.log("request: " + JSON.stringify(event));

    // Request Body
    requestBody = event.body;

    if (requestBody !== undefined && requestBody !== null) {

        // Set 'test-status' field in the request to test sending a specific response status code (e.g., 503)
        responseCode = JSON.parse(requestBody)['test-status'];
    }

    // Path Parameters
    pathParams = event.path;

    // Query String Parameters
    queryStringParams = event.queryStringParameters;

    // Header Parameters
    headerParams = event.headers;

    if (event.requestContext !== null && event.requestContext !== undefined) {

        var requestContext = event.requestContext;

        // API Gateway Stage
        stage = requestContext.stage;

        // Unique Request ID
        requestId = requestContext.requestId;

        // Resource Path
        resourcePath = requestContext.resourcePath;

        var identity = requestContext.identity;

        // Amazon Cognito User Identity
        cognitoIdentityId = identity.cognitoIdentityId;

        // Source IP
        sourceIp = identity.sourceIp;

        // User-Agent
        userAgent = identity.userAgent;
    }

    // API Gateway Stage Variables
    stageVariables = event.stageVariables;

    // HTTP Method (e.g., POST, GET, HEAD)
    httpMethod = event.httpMethod;

    // TODO: Put your application logic here...

    let params = {
        Item:{
            "prop1":0,
            "prop2":"text"
        },
        TableName:"testTable"
    };

    docClient.put(params, function(data, err){
        if(err)
            responseCode = 500;
        else
            {
                responseCode = 200;
                context.succeed(data);
            }
    });

    // For demonstration purposes, we'll just echo these values back to the client
    var responseBody = {
        requestBody : requestBody,
        pathParams : pathParams,
        queryStringParams : queryStringParams,
        headerParams : headerParams,
        stage : stage,
        stageVariables : stageVariables,
        cognitoIdentityId : cognitoIdentityId,
        httpMethod : httpMethod,
        sourceIp : sourceIp,
        userAgent : userAgent,
        requestId : requestId,
        resourcePath : resourcePath
    };

    var response = {
        statusCode: responseCode,
        headers: {
            "x-custom-header" : "custom header value"
        },
        body: JSON.stringify(responseBody)
    };
    console.log("response: " + JSON.stringify(response))
    context.succeed(response);
};

this doesn't put the item to the table for some reason. I gave the necessary permissions using the roles part, anything I am missing?

**responseCode is only for testing purposes.

Edit: tried AWS node.js lambda request dynamodb but no response (no err, no return data) and doesn't work either.

Edit2: Added the full handler code. (it the default generated code when creating first AWS lambda).

2
Can you please post your whole Lambda handler? I have some some things in mind but need to check your handler first.Thales Minussi
Thanks, I added the full code (the automatically generated one from AWS). I should mention that this is just a test function to learn how to access the DB using lambda. (doing a university project and want to use a cloud DB)Daniel Toledano
Please also add the exact error message you are receiving when executing this code.Sébastien Stormacq
no error message at all.. it just doesn't add the item to the DB.Daniel Toledano
I was just thinking about that too. Thanks for the suggestion. I will reach out to the doc teamSébastien Stormacq

2 Answers

1
votes

I have refactored some bits of your code to look much simpler and use async/await (make sure to select Node 8.10 as the running environment for your function) instead of callbacks. I also got rid of the context and callback parameters, as they were used for older versions of NodeJS. Once you're using Node 8+, async/await should be the default option.

Also, it is possible to chain a .promise() on docClient.putItem, so you can easily await on it, making your code way simpler. I have left only the DynamoDB part (which is what is relevant to your question)

'use strict';
console.log("Loading function");

const AWS = require('aws-sdk');
const docClient = new AWS.DynamoDB.DocumentClient({region:process.env.MOBILE_HUB_PROJECT_REGION});

exports.handler = async (event) => {

    let params = {
        Item:{
            "prop0":1,
            "prop2":"text"
        },
        TableName:"testTable"
    };

    try {
      await docClient.put(params).promise();
    } catch (e) {
      console.log(e)
      return {
        messsage: e.message
      }
    }

    return { message: 'Data inserted successfully' };

};

Things to keep in mind if still it does not work:

  1. Make sure your Lambda function has the right permissions to insert items on DynamoDB (AmazonDynamoDBFullAccess will do it)

  2. You ALWAYS have to provide the partition key when inserting items to DynamoDB. On your example, the JSON only has two properties: prop1 and prop2. If none of them are the partition key, your code will certainly fail.

  3. Make sure you table also exists

If you code fails, just check CloudWatch logs as any exception is now captured and printed out on the console.

1
votes

The reason why no data is written in the table is because the call to DynamoDB put is asynchronous and will return by calling your callback. But during that time, the rest of the code continues to execute and your function eventually finish before the call to DynamoDB has a chance to complete.

You can use the await / async keywords to make your code sychronous :

async function writeToDynamoDB(params) {
 return new Promise((resolve,reject) => {
    docClient.put(params, function(data, err){
        if(err)
            reject(500);
        else
            resolve(data);
     });
 });
}

let params = ...
var data = await writeToDynamoDB(params)

You can find sample code I wrote (in Typescript) at https://github.com/sebsto/maxi80-alexa/blob/master/lambda/src/DDBController.ts