使用AWS DynamoDB及如下Body Mapping Template时,API Gateway数据被覆盖问题
Hey there, let's figure out why your DynamoDB data is getting unexpectedly overwritten when using API Gateway's Body Mapping Template. I’ve run into this exact headache before, so here are the most common culprits and straightforward fixes:
PutItem instead of UpdateItem This is the #1 reason for accidental overwrites. PutItem replaces the entire item if the primary key already exists—so even if you only meant to update one field, it’ll wipe out all existing attributes and replace them with what’s in your request.
Bad (PutItem example):
{ "TableName": "YourTable", "Item": { "id": {"S": "$input.path('$.id')"}, "userData": {"S": "$input.path('$.userData')"} } }
If an item with that id exists, this will completely replace it.
Good (UpdateItem fix):
Use UpdateItem to modify only specific attributes without touching the rest of the item:
{ "TableName": "YourTable", "Key": { "id": {"S": "$input.path('$.id')"} }, "UpdateExpression": "SET #userData = :userData", "ExpressionAttributeNames": {"#userData": "userData"}, "ExpressionAttributeValues": {":userData": {"S": "$input.path('$.userData')"}} }
Even with UpdateItem, you might accidentally modify items you didn’t intend to. Adding a ConditionExpression acts as a guard rail to prevent changes unless specific criteria are met.
For example, if you only want to create a new item (not update an existing one), add this line to your PutItem or UpdateItem template:
"ConditionExpression": "attribute_not_exists(id)"
This will throw an error if the id already exists, stopping the overwrite dead in its tracks.
You can also get more granular—like only updating an item if a specific attribute matches a value:
"ConditionExpression": "#status = :pending", "ExpressionAttributeNames": {"#status": "status"}, "ExpressionAttributeValues": {":pending": {"S": "PENDING"}}
If your DynamoDB items have nested structures, updating the entire nested object will overwrite all its sub-attributes, not just the ones you changed.
Bad example:
If your item looks like {"user": {"name": "Alice", "age": 30}}, and your template uses:
"UpdateExpression": "SET #user = :user", "ExpressionAttributeValues": {":user": {"M": {"age": {"N": "31"}}}}
This will erase the name field entirely, leaving only {"user": {"age": 31}}.
Fix:
Update nested attributes directly using dot notation:
"UpdateExpression": "SET #user.#age = :age", "ExpressionAttributeNames": {"#user": "user", "#age": "age"}, "ExpressionAttributeValues": {":age": {"N": "$input.path('$.user.age')"}}
This way, only the age field gets updated, and name stays intact.
Double-check that your API requests aren’t sending duplicate primary key values (partition key + sort key if you’re using composite keys). Even with UpdateItem, if the key matches an existing item, it’ll modify that item—which can feel like an overwrite if you didn’t mean to touch it.
Add validation in your frontend or API Gateway template to ensure unique keys where needed, or use a ConditionExpression to block updates to unintended items.
Sometimes the issue is a typo or incorrect input path in your Body Mapping Template. For example, if you use $input.json('$') to pass the entire request body as the Item in PutItem, any missing fields in the request will replace existing fields with null (or remove them entirely, depending on your DynamoDB settings).
Instead, explicitly map only the fields you want to update, or stick with UpdateItem to avoid replacing the whole item.
Start with checking which operation you’re using (PutItem vs UpdateItem)—that’s almost always the first fix. Then add condition expressions to guard against unintended changes, and make sure you’re targeting specific attributes instead of replacing entire items.
内容的提问来源于stack exchange,提问作者san shirke

