Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AWS API gateway body mapping template for dynamodb map

I am trying to figure out how to insert dynamic data into a dynamodb table via an API Gateway in AWS. Currently I have a dynamodb table and an API endpoint setup that accepts a POST like so.

POST https://{unique-id}.execute-api.us.east-1.amazonaws.com/notification/events

{
  "reference_number": 99,
  "purchase_date": "1/1/2017"
}

I've setup a body mapping template in the API gateway to massage the data into the dynamodb.

{ 
    "TableName": "Events",
    "Item": {
        "reference_number": {
            "N": "$input.path('$.reference_number')"
        },
        "purchase_date": {
            "S": "$input.path('$.purchase_date')"
        }
    }
}

The above works and saves to the table.

Suppose I add the event hash to my json (which can change based on events).

{
  "reference_number": 99,
  "purchase_date": "1/1/2017",
  "event": {
     "name": "purchase",
     "items": [1,3,6],
     "info": {
       "currencyID": "USD",
       "countryID": "US"
     }
  }
}

How do I save the event attribute to a Map in dynamodb using the API Gateway Body mapping template syntax?

{ 
    "TableName": "Events",
    "Item": {
        "reference_number": {
            "N": "$input.path('$.reference_number')"
        },
        "purchase_date": {
            "S": "$input.path('$.purchase_date')"
        },
        "event":{
            "M": "$input.path('$.event')"
        }
    }
}

The above template gives me the following error. "Expected map or null"

like image 992
MikeV Avatar asked Feb 06 '17 22:02

MikeV


People also ask

Can API gateway talk directly to DynamoDB?

Amazon API Gateway will help us to create a REST endpoint for our messages resource. However, the API Gateway solution can not fetch data directly from DynamoDB.

How do I add a mapping template to API gateway?

Navigate to the API Gateway console, choose the StoreFront API and open the GET method of the /orders resource. On the Method Execution details page, choose Integration Response. Expand the default response mapping (HTTP status 200), and expand the Mapping Templates section. Choose Add Mapping Template.

What is VTL in API gateway?

Map request and response payloads between method and integration. API Gateway uses Velocity Template Language (VTL) engine to process body mapping templates for the integration request and integration response.


2 Answers

It looks like DynamoDB API actually requires the value of an 'M' attribute to be a Map of String -> AttributeValue. Unfortunately you can't pass the raw JSON. You'll have to manually map the whole event object to make the DDB API happy.

http://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_AttributeValue.html#DDB-Type-AttributeValue-M

One possible workaround would be to stringify the event object and write it as type S but that would of course require the reader to expect that behavior.

{ 
    "TableName": "Events",
    "Item": {
        "reference_number": {
            "N": "$input.path('$.reference_number')"
        },
        "purchase_date": {
            "S": "$input.path('$.purchase_date')"
        },
        "event":{
            "S": "$util.escapeJavaScript($input.json('$.event'))"
        }
    }
}
like image 147
jackko Avatar answered Sep 29 '22 06:09

jackko


As it seems you finally did. I reckon the best option is to create a simple lambda function between you API and dynamoDB. Leaving the mapping work up to the aws-sdk.

In that case, the body mapping template in the API gateway would be as simple as this:

$input.body

And the function won't be much more complicated. I used a javascript function:

var AWS = require("aws-sdk");

var docClient = new AWS.DynamoDB.DocumentClient();
var tableName = "tableName";

var saveData = function (data) {

  var params = {
    TableName: tableName,
    Item: data
  };

  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));
    }
  });

};

exports.handler = function (event) {
  try {
    console.log("Processing event: ", event);
    saveData(event);
  } catch (e) {
    console.error("Processed unsuccessfully", e, e.stack);
  }
};

http://docs.aws.amazon.com/amazondynamodb/latest/gettingstartedguide/GettingStarted.NodeJs.03.html

like image 45
Pablo Martinez Avatar answered Sep 29 '22 08:09

Pablo Martinez