Add Delete Support and Keep the Dashboard in Sync
Add a delete endpoint for uploaded files, removing them from both S3 and DynamoDB, and keep your frontend dashboard updated.
All services used in this lesson are covered by the AWS Free Tier.
AWS Services Used
Learning Outcomes
By the end of this lesson, you will be able to:
- Add a delete endpoint for uploaded files.
- Delete the S3 object and its DynamoDB metadata record from Lambda.
- Explain why the API route should use an HTTP
DELETEmethod. - Update the frontend so the list and detail view stay in sync after deletion.
- Explain the importance of deleting from both storage and metadata.
The Core Idea
Your dashboard can already upload files, store metadata, list files, and open individual files. The next logical step is delete support: when a user deletes a file, your backend should remove the object from S3 and remove the matching metadata row from DynamoDB.
Important Assumption
For this lesson, assume your upload bucket is not using S3 versioning. In a versioning-enabled bucket, deleting the current object without specifying a version ID does not permanently remove all versions. Instead, S3 creates a delete marker, which changes the behavior from the simpler case.
Why Delete Both Places?
If you delete only the S3 object and keep the DynamoDB item, your dashboard will show stale metadata. If you delete only the DynamoDB item and keep the S3 object, the file still exists in storage even though your UI no longer knows about it.
Part 1: Add the API Route
Create a new HTTP API route: DELETE /metadata. API Gateway HTTP API routes are defined by an HTTP method plus a resource path.
Part 2: Update API CORS
Because your browser frontend will now send a DELETE request, your HTTP API CORS configuration must allow the DELETE method.
Update your settings to allow:
- Allowed Origins: Your frontend origin
- Allowed Methods:
GET,POST,DELETE - Allowed Headers:
Content-Type
Part 3: Create the Delete Lambda Function
Create a new Lambda function with environment variables TABLE_NAME and UPLOAD_BUCKET. Use this Python code:
import json
import os
import boto3
s3_client = boto3.client("s3")
dynamodb = boto3.resource("dynamodb")
table = dynamodb.Table(os.environ["TABLE_NAME"])
upload_bucket = os.environ["UPLOAD_BUCKET"]
def lambda_handler(event, context):
try:
body = json.loads(event.get("body") or "{}")
except json.JSONDecodeError:
return {
"statusCode": 400,
"headers": {"Content-Type": "application/json"},
"body": json.dumps({"error": "Invalid JSON body"})
}
bucket = body.get("bucket")
object_key = body.get("key")
if not bucket or not object_key:
return {
"statusCode": 400,
"headers": {"Content-Type": "application/json"},
"body": json.dumps({"error": "Missing required fields: bucket and key"})
}
if bucket != upload_bucket:
return {
"statusCode": 400,
"headers": {"Content-Type": "application/json"},
"body": json.dumps({"error": "Bucket does not match configured upload bucket"})
}
# 1. Delete from S3
s3_client.delete_object(
Bucket=bucket,
Key=object_key
)
# 2. Delete from DynamoDB
table.delete_item(
Key={
"bucket": bucket,
"object_key": object_key
}
)
return {
"statusCode": 200,
"headers": {"Content-Type": "application/json"},
"body": json.dumps({
"message": "Deleted successfully",
"bucket": bucket,
"object_key": object_key
})
}
Part 4: Give the Function Permissions
The function needs permission to delete both the S3 object and the DynamoDB row.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DeleteUploadedObjects",
"Effect": "Allow",
"Action": ["s3:DeleteObject"],
"Resource": "arn:aws:s3:::YOUR_UPLOAD_BUCKET/incoming/*"
},
{
"Sid": "DeleteMetadataItems",
"Effect": "Allow",
"Action": ["dynamodb:DeleteItem"],
"Resource": "arn:aws:dynamodb:REGION:ACCOUNT_ID:table/upload_metadata"
}
]
}
Part 5: Frontend Integration
Update your frontend to include a deleteFile function using the DELETE method. The simplest UI strategy after a successful deletion is to reload the list. This ensures the UI accurately reflects the source of truth on the backend.
Part 6: Test the Full Flow
- Load your uploaded file list.
- Open details for one file.
- Click Delete and confirm.
- Verify the file disappears from the list and the detail panel is cleared.
Lab Checklist
| Step | Success Condition |
|---|---|
| Create DELETE route | Route exists in HTTP API |
| Add Lambda integration | API requests reach the delete function |
| Add s3:DeleteObject permission | Lambda can remove the S3 object |
| Add dynamodb:DeleteItem permission | Lambda can remove the metadata row |
| Update frontend | Delete button appears and works |
| Refresh list | Deleted file disappears from UI |
Micro-activity 1: Reflection
Think about it
After the lab, reflect: Which object key did you delete? Did the API return success or an error? Did the item disappear from the list? When you refreshed the page, was the file still gone?
Micro-activity 2: Consistency Rule
Think about it
Why is deleting both the S3 object and the DynamoDB metadata row better than deleting only one? Why is reloading the list after delete a good UI strategy?
Summary
In this lesson, you added delete support to the upload dashboard. You learned that API Gateway routes by method and path, and that staying in sync requires removing data from both storage (S3) and metadata (DynamoDB).