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"
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.
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'))"
}
}
}
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
For my requirement (saving input body), the mapping template is
"rawdata": {
"M": $input.body
}
Note that there are no quotes for input body.
And the data should be in Dynamodb format, for eg
{"username":{"S":"Vishnu"}}
You could use js lib like dynamodb-marshaller to convert json to Dynamodb format. Hope this helps.
来源:https://stackoverflow.com/questions/42078059/aws-api-gateway-body-mapping-template-for-dynamodb-map