Chúng ta sẽ tạo một hàm Lambda để ghi dữ liệu vào bảng DynamoDB và tải ảnh lên S3.
Hàm này yêu cầu hai S3 bucket bổ sung:
Mở tệp template.yaml trong thư mục fcaj-book-shop.
Thêm các tham số sau vào phần Parameters:
bookImageShopBucketName:
Type: String
Default: book-image-shop-by-tranvix
bookImageResizeShopBucketName:
Type: String
Default: book-image-resize-shop-by-tranvix

Thêm các tài nguyên S3 bucket vào phần Resources:
BookImageShop:
Type: AWS::S3::Bucket
Properties:
BucketName: !Ref bookImageShopBucketName
PublicAccessBlockConfiguration:
BlockPublicAcls: false
BlockPublicPolicy: false
IgnorePublicAcls: false
RestrictPublicBuckets: false
BookImageResizeShop:
Type: AWS::S3::Bucket
Properties:
BucketName: !Ref bookImageResizeShopBucketName
PublicAccessBlockConfiguration:
BlockPublicAcls: false
BlockPublicPolicy: false
IgnorePublicAcls: false
RestrictPublicBuckets: false
CorsConfiguration:
CorsRules:
- AllowedHeaders:
- "*"
AllowedMethods:
- GET
- PUT
- POST
- DELETE
AllowedOrigins:
- "*"

Thêm bucket policy cho resize bucket và hàm Lambda BookCreate:
BookImageResizeShopPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref BookImageResizeShop
PolicyDocument:
Version: 2012-10-17
Statement:
- Action:
- "s3:GetObject"
Effect: Allow
Principal: "*"
Resource: !Join
- ""
- - "arn:aws:s3:::"
- !Ref BookImageResizeShop
- /*

Thêm tài nguyên Lambda function BookCreate:
BookCreate:
Type: AWS::Serverless::Function
Properties:
CodeUri: fcaj-book-shop/book_create
Handler: book_create.lambda_handler
Runtime: python3.13
Environment:
Variables:
BUCKET_NAME: !Ref BookImageShop
BUCKET_RESIZE_NAME: !Ref BookImageResizeShop
TABLE_NAME: !Ref BooksTable
FunctionName: book_create
Architectures:
- x86_64
Policies:
- Statement:
- Sid: BookCreateItem
Effect: Allow
Action:
- dynamodb:PutItem
- s3:PutObject
Resource:
- !Sub arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/${booksTableName}
- !Join
- ""
- - "arn:aws:s3:::"
- !Ref BookImageShop
- /*

Tài nguyên này định nghĩa một Lambda function tên book_create với:
BUCKET_NAME, BUCKET_RESIZE_NAME và TABLE_NAMETạo cấu trúc thư mục như sau:
fcaj-book-shop
├── fcaj-book-shop
│ ├── books_list
│ │ └── books_list.py
│ └── book_create
│ ├── book_create.py
│ └── requirements.txt
└── template.yaml
import base64
from multipart import MultipartParser
from io import BytesIO
import boto3
import os
BUCKET = os.environ['BUCKET_NAME']
BUCKET_RESIZE = os.environ['BUCKET_RESIZE_NAME']
TABLE = os.environ['TABLE_NAME']
s3_client = boto3.client('s3')
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table(TABLE)
header_res = {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "OPTIONS,POST,GET,DELETE",
"Access-Control-Allow-Headers": "Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token",
}
def parse_multipart(body, boundary):
parser = MultipartParser(stream=body, boundary=boundary)
fields = {}
files = {}
for part in parser:
if part.filename:
files[part.name] = {
'file-name': part.filename,
'content': part.raw
}
else:
fields[part.name] = part.value
return fields, files
def upload_to_s3(key, bucket, body):
try:
s3_client.put_object(Key=key, Bucket=bucket, Body=body)
except Exception as e:
print(f"Error uploading image to S3: {e}")
raise Exception(f'Error uploading image to S3: {e}')
def create_new_item(table, item):
try:
table.put_item(Item=item)
except Exception as e:
print(f"Error creating new item in DynamoDB table: {e}")
raise Exception(f'Error creating new item in DynamoDB table: {e}')
def lambda_handler(event, context):
content_type = event['headers'].get(
'Content-Type', '') or event['headers'].get('content-type', '')
try:
body = event['body']
if event['isBase64Encoded']:
body = BytesIO(base64.b64decode(body))
boundary = content_type.split("boundary=")[1]
fields, files = parse_multipart(body, boundary)
# Upload image to s3
file_name = files['image']['file-name']
file_content = files['image']['content']
upload_to_s3(file_name, BUCKET, file_content)
s3_url = f'https://{BUCKET_RESIZE}.s3.amazonaws.com/{file_name}'
# Create new item in DB
item = {
'id': fields.get('id', 0),
'rv_id': 0,
'name': fields.get('name', ''),
'author': fields.get('author', ''),
'price': fields.get('price', ''),
'category': fields.get('category', ''),
'description': fields.get('description', ''),
'image': s3_url
}
create_new_item(table, item)
return {
"statusCode": 200,
"headers": header_res,
"body": "Successfully created item!",
}
except Exception as e:
print(f"Error processing form data: {e}")
raise Exception(f'Error processing form data: {e}')

Tạo tệp requirements.txt trong thư mục book_create với nội dung:
multipart

Thư viện multipart được yêu cầu để phân tích dữ liệu multipart form (tải lên tệp) được gửi từ frontend. SAM sẽ cài đặt dependency này trong quá trình sam build.
Chạy các lệnh sau để build và validate SAM template:
sam validate
sam build

Triển khai stack đã cập nhật:
sam deploy
Changeset sẽ hiển thị các tài nguyên mới được thêm:
BookCreateRole (AWS::IAM::Role)BookCreate (AWS::Lambda::Function)BookImageShop (AWS::S3::Bucket)BookImageResizeShop (AWS::S3::Bucket)BookImageResizeShopPolicy (AWS::S3::BucketPolicy)Nhập y để xác nhận triển khai.

Chờ quá trình triển khai hoàn tất. Bạn sẽ thấy thông báo Successfully created/updated stack.

Mở Lambda console. Bạn sẽ thấy cả hai hàm books_list và book_create.

Nhấp vào hàm book_create. Xem phần Code source.

Xem phần Function overview hiển thị sơ đồ function.

Nhấp vào tab Configuration, sau đó chọn Environment variables. Xác nhận 3 biến môi trường đã được thiết lập đúng:
BUCKET_NAME = book-image-shop-by-tranvixBUCKET_RESIZE_NAME = book-image-resize-shop-by-tranvixTABLE_NAME = Books
Chọn Permissions từ menu bên trái. Nhấp vào tên execution role (ví dụ: fcaj-book-shop-BookCreateRole-...).

Tại trang IAM Role, kiểm tra phần Permissions policies. Bạn sẽ thấy:

Nhấp vào BookCreateRolePolicy0 để mở rộng. Xem chi tiết policy JSON cấp quyền dynamodb:PutItem và s3:PutObject.

Mở S3 console. Tìm kiếm book-image. Bạn sẽ thấy cả hai bucket đã được tạo:

Nhấp vào book-image-resize-shop-by-tranvix. Chuyển sang tab Permissions. Xác nhận Bucket policy cho phép truy cập công khai s3:GetObject.

Xem chi tiết Bucket policy JSON.

Cuộn xuống phần Cross-origin resource sharing (CORS). Xác nhận cấu hình CORS cho phép tất cả origin và method (GET, PUT, POST, DELETE).
