A FastAPI-based Lambda function that provides a RESTful API interface to DynamoDB.
- Python 3.9
- AWS CLI configured with appropriate credentials
- A DynamoDB table named "Items" (or update the table name in the code)
-
Clone the repository
-
Install dependencies locally (if needed):
pip install -r requirements_local.txt
-
Deploy to AWS Lambda:
sh deploy.sh
The deploy script will:
- Create a clean package directory
- Install dependencies
- Package the Lambda function with dependencies
- Update the Lambda function code
The Lambda function needs permissions to access DynamoDB. Add this inline policy to your Lambda function's execution role:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"dynamodb:GetItem",
"dynamodb:PutItem",
"dynamodb:DeleteItem",
"dynamodb:Scan",
"dynamodb:Query",
"dynamodb:UpdateItem"
],
"Resource": "arn:aws:dynamodb:*:*:table/Items"
}
]
}
To add the policy:
- Go to AWS Lambda console
- Click on your function
- Go to "Configuration" > "Permissions"
- Click on the IAM role link
- In IAM console, click "Add permissions" > "Create inline policy"
- Switch to JSON editor and paste the policy above
- Name it (e.g., "DynamoDBAccess") and create the policy
The function can be tested using API Gateway v2 formatted test events. Here are examples for different operations:
{
"version": "2.0",
"routeKey": "GET /items",
"rawPath": "/items",
"rawQueryString": "",
"headers": {
"accept": "*/*",
"content-length": "0",
"host": "your-api-id.execute-api.region.amazonaws.com",
"user-agent": "curl/7.64.1",
"x-amzn-trace-id": "Root=1-5e6722a7-cc56xmpl46db7ae02d4da47dd",
"x-forwarded-for": "1.2.3.4",
"x-forwarded-port": "443",
"x-forwarded-proto": "https"
},
"requestContext": {
"accountId": "123456789012",
"apiId": "api-id",
"domainName": "your-api-id.execute-api.region.amazonaws.com",
"domainPrefix": "your-api-id",
"http": {
"method": "GET",
"path": "/items",
"protocol": "HTTP/1.1",
"sourceIp": "1.2.3.4",
"userAgent": "curl/7.64.1"
},
"requestId": "JKJaXmPLvHcESHA=",
"routeKey": "GET /items",
"stage": "$default",
"time": "10/Mar/2024:13:40:52 +0000",
"timeEpoch": 1583856052000
},
"isBase64Encoded": false
}
{
"version": "2.0",
"routeKey": "POST /items",
"rawPath": "/items",
"rawQueryString": "",
"headers": {
"accept": "application/json",
"content-type": "application/json",
"content-length": "39",
"host": "your-api-id.execute-api.region.amazonaws.com",
"user-agent": "curl/7.64.1",
"x-amzn-trace-id": "Root=1-5e6722a7-cc56xmpl46db7ae02d4da47dd",
"x-forwarded-for": "1.2.3.4",
"x-forwarded-port": "443",
"x-forwarded-proto": "https"
},
"requestContext": {
"accountId": "123456789012",
"apiId": "api-id",
"domainName": "your-api-id.execute-api.region.amazonaws.com",
"domainPrefix": "your-api-id",
"http": {
"method": "POST",
"path": "/items",
"protocol": "HTTP/1.1",
"sourceIp": "1.2.3.4",
"userAgent": "curl/7.64.1"
},
"requestId": "JKJaXmPLvHcESHA=",
"routeKey": "POST /items",
"stage": "$default",
"time": "10/Mar/2024:13:40:52 +0000",
"timeEpoch": 1583856052000
},
"body": "{\"id\": \"test-item-1\", \"name\": \"Test Item\"}",
"isBase64Encoded": false
}
To use these test events:
- Go to AWS Lambda console
- Select your function
- Click the "Test" tab
- Click "Create new event"
- Give it a name (e.g., "GetItemsTest" or "CreateItemTest")
- Paste the appropriate JSON
- Click "Save" and "Test"
The API supports both unversioned (default) and versioned endpoints. You can access the same functionality through either version:
- GET /items - List all items
- GET /items/{item_id} - Get a specific item
- GET /items/{item_id}/{property_name} - Get a specific property of an item
- POST /items - Create a new item
- PUT /items/{item_id} - Update an item
- DELETE /items/{item_id} - Delete an item
The v1 API introduces pagination for the items endpoint while maintaining the same functionality for other endpoints:
# Get first page
GET /v1/items?limit=5
Response:
{
"items": [...],
"next_cursor": "base64_encoded_cursor"
}
# Get next page using the cursor
GET /v1/items?limit=5&cursor=<next_cursor>
Response:
{
"items": [...],
"next_cursor": "base64_encoded_cursor_or_null"
}
Note: When next_cursor is null, there are no more items to retrieve.
Other v1 endpoints remain unchanged:
- GET /v1/items/{item_id} - Get a specific item
- GET /v1/items/{item_id}/{property_name} - Get a specific property of an item
- POST /v1/items - Create a new item
- PUT /v1/items/{item_id} - Update an item
- DELETE /v1/items/{item_id} - Delete an item
Note: In order for the API gateway to work, each of these routes (both unversioned and v1) needs to be added explicitly in the API Gateway console and attached to the Lambda function.
The function uses Loguru for logging, configured to:
- Write logs to CloudWatch
- Store rotating logs in /tmp/logs (Lambda's writable directory)
- Include timestamps, log levels, and detailed context
Key dependencies (see requirements.txt for versions):
- fastapi - Web framework
- pydantic - Data validation
- mangum - AWS Lambda/API Gateway integration
- boto3 - AWS SDK (included in Lambda runtime)