Reputation: 87
How can I insert multiple rows in dynamodb using body mapping template of API gateway?
Input to my code is "xyz 1,abc 2" which has information about 2 rows to be inserted.
Only second record which is "abc 2" is getting stored, I want both records to be inserted in the table. Below is the code I have written
#set($rawAPIData = $input.path('$'))
#set ($bulk = $rawAPIData.split(","))
{
"TableName": "tablename",
#foreach( $records in $bulk)
#set ($s = $records.split(" "))
"Item": {
"col1": {
"S": "$s.get(0)"
},
"col2": {
"S": "$s.get(1)"
}
}
#if( $foreach.hasNext ), #end
#end
}
I'm new to this, suggestion would really help
Upvotes: 0
Views: 2303
Reputation: 31
Thanks for the ideas. Loved @Gerard's approach. Incorporated both the OP's and Gerard's approach for my use case which was slightly different, I didn't want the whole splitting logic and was trying to implement it without a lambda as well.
Example Request Body:
{
"fruit": {
"fruitName": "Apple",
"fruitValue": "Sweet"
},
"varieties": [
{
"varietyOrigin": "Tropical",
"varietyName": "Mango",
"varietyValue": "Juicy"
},
{
"varietyOrigin": "Berry",
"varietyName": "Strawberry",
"varietyValue": "Tangy"
}
]
}
Velocity Template:
{
"RequestItems": {
"<tablename>": [
#foreach($item in $input.path('$.varieties'))
{
"PutRequest": {
"Item": {
"fruit": {
"S": "$util.escapeJavaScript($input.path('$.fruit.fruitName'))#$util.escapeJavaScript($input.path('$.fruit.fruitValue'))"
},
"variety": {
"S": "$util.escapeJavaScript($item.varietyOrigin)#$util.escapeJavaScript($item.varietyName)#$util.escapeJavaScript($item.varietyValue)"
}
}
}
}
#if($foreach.hasNext),#end
#end
]
}
}
Upvotes: 1
Reputation: 87
I used the similar approach as @Gerand, but I solved it using lambda. Here is the working code:
'use strict';
const AWS = require("aws-sdk");
const dynamodb = new AWS.DynamoDB();
exports.handler = (event, context, callback) => {
var data=event.data;
var bulk = data.split(",");
var toSave = [];
for(var i = 0; i < bulk.length; i++) {
var s=bulk[i].split(" ");
var item = {
"col1": {
S: s[0]
},
"col2": {
S: s[1]
}
};
toSave.push(item);
}
var items = [];
for(var i = 0; i < toSave.length; i++) {
items[i] = {
PutRequest: { Item: toSave[i] }
}
}
var params = {
RequestItems: {
'table_name': items
}
};
dynamodb.batchWriteItem(params, function(err, data) {
console.log("Response from DynamoDB");
if(err) console.log(err);
else console.log(data);
});
};
Upvotes: 0
Reputation: 111
This AWS guide shows how to use API Gateway as a proxy for DynamoDB. It's similar the approach you are trying to take. As a suggestion, it might be better have your api focus on a single row at a time, rather than splitting multiple inputs on ,
. For example it would simplify your template somewhat to send requests similar to those found in the guide.
Example Request Body:
{
"col1": "xyz",
"col2": "1"
}
Template (derived from your template code):
{
"TableName": "tablename",
"Item": {
"col1": {
"S": "$input.path('$.col1')"
},
"col2": {
"S": "$input.path('$.col2')"
}
}
}
However, if you want to stick to operating on multiple items, The BatchWriteItem documentation would be worth a read. Following the example, I think this should be your body template:
#set($rawAPIData = $input.path('$'))
#set ($bulk = $rawAPIData.split(","))
{
"RequestItems": {
"tablename": [
#foreach($records in $bulk)
#set ($s = $records.split(" "))
{
"PutRequest": {
"Item": {
"col1": {
"S": "$s.get(0)"
},
"col2": {
"S": "$s.get(1)"
}
}
}
}
#if( $foreach.hasNext ),
#end
]
}
#end
}
Upvotes: 5