
Building an Event-Driven REST API with AWS Lambda, API Gateway, and DynamoDB
A step-by-step practical guide to deploying a production-ready serverless REST API using Amazon API Gateway HTTP APIs, AWS Lambda, and Amazon DynamoDB, including error handling and IAM security best practices.
Building a Resilient Serverless REST API with AWS Lambda, API Gateway, and DynamoDB
Overview
Modern cloud architectures prioritize decoupling, auto-scaling, and pay-per-use economics. In this walkthrough, we build a resilient CRUD endpoint using Amazon API Gateway (HTTP API), AWS Lambda, and Amazon DynamoDB for single-digit millisecond data persistence.
Architectural Breakdown
- API Gateway (HTTP API): Low-latency entry point handling routing, throttling, and CORS.
- AWS Lambda: Ephemeral compute running business logic on-demand.
- Amazon DynamoDB: Fully managed NoSQL key-value store configured with on-demand capacity.
Prerequisites
- An active AWS Account with permissions for Lambda, API Gateway, and DynamoDB.
- AWS CLI installed and configured locally (
aws configure). - Node.js (v18+) or Python installed.
Step 1: Create the DynamoDB Table
Set up an on-demand table to eliminate manual capacity planning:
1
2
3
4
5
aws dynamodb create-table \
--table-name ItemsTable \
--attribute-definitions AttributeName=itemId,AttributeType=S \
--key-schema AttributeName=itemId,KeyType=HASH \
--billing-mode PAY_PER_REQUEST
Step 2: Implement the Lambda Handler
Here is a clean Node.js handler using the modular AWS SDK v3:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
import {
DynamoDBDocumentClient,
PutCommand,
GetCommand
} from "@aws-sdk/lib-dynamodb";
const client = new DynamoDBClient({});
const docClient = DynamoDBDocumentClient.from(client);
const TABLE_NAME = process.env.TABLE_NAME || "ItemsTable";
export const handler = async (event) => {
const method = event.requestContext?.http?.method;
const path = event.rawPath;
try {
if (method === "POST" && path === "/items") {
const body = JSON.parse(event.body || "{}");
await docClient.send(
new PutCommand({
TableName: TABLE_NAME,
Item: body,
})
);
return {
statusCode: 201,
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
message: "Item created successfully"
}),
};
}
if (method === "GET" && path.startsWith("/items/")) {
const itemId = path.split("/")[2];
const result = await docClient.send(
new GetCommand({
TableName: TABLE_NAME,
Key: { itemId },
})
);
if (!result.Item) {
return {
statusCode: 404,
body: JSON.stringify({
message: "Item not found"
}),
};
}
return {
statusCode: 200,
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(result.Item),
};
}
return {
statusCode: 400,
body: JSON.stringify({
message: "Unsupported route"
}),
};
} catch (err) {
console.error("Execution error:", err);
return {
statusCode: 500,
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
error: err.message
}),
};
}
};
Step 3: Best Practices & Security
1. Least-Privilege IAM Roles
Scope down the Lambda execution role.
Do not use managed administrator policies. Grant only the permissions required by the Lambda function, such as:
dynamodb:PutItemdynamodb:GetItem
Restrict these permissions to the specific DynamoDB table ARN.
2. Cold Start Optimization
- Keep dependencies minimal.
- Use modern Lambda runtimes.
- Avoid unnecessarily large external libraries.
- Reuse SDK clients outside the Lambda handler so they can be reused across invocations.
3. Structured Observability
Log events as structured JSON objects to enable targeted queries in CloudWatch Logs Insights.
Example:
1
2
3
4
5
console.log(JSON.stringify({
level: "INFO",
action: "CREATE_ITEM",
timestamp: new Date().toISOString()
}));
Summary
This serverless architecture provides a highly scalable, low-maintenance API backend with minimal operational overhead.
The architecture can be extended by adding:
- Amazon EventBridge for asynchronous event publishing.
- AWS WAF to protect the public API.
- Amazon CloudWatch for monitoring and observability.
- Amazon Cognito for authentication and authorization.
- Additional DynamoDB operations for a complete CRUD implementation.
Architecture Flow
1
2
3
4
5
6
7
8
9
10
11
12
13
Client
|
v
API Gateway (HTTP API)
|
v
AWS Lambda
|
v
Amazon DynamoDB
|
v
CloudWatch Logs
Enjoyed reading this content? Let the author know!
Your likes, comments, shares, and saves help creators reach more builders.
Loading recommendations
Loading article