Ravindra BagaleCourses & study guides मराठी Track your progress

Project: Build a Contact Form API with Lambda, DynamoDB and SNS (Source Code)

Every business site has a Contact form. Save the message in DynamoDB and email yourself with SNS — serverless, region ap-south-1.

What you'll learn in this chapter

  • Wire contact POST API
  • Persist in DynamoDB
  • SNS email alert
  • Test and clean up

1. Everyday example

Why do we need this?

A coaching-class site: visitor sends name, email, message. You want the row saved and a mail ping — without an EC2 running all night.

What is it?

POST /contact → Lambda → PutItem + sns.publish to a topic with your email subscribed.

PathClientPOST JSONAPI GatewayLambdavalidate + PutItemSNS topicemail
Confirm the SNS subscription email once.

Download: contact-form-api.zip

2. Lab

How to do it (step by step)

Region ap-south-1.

A. DynamoDB + SNS

  1. Table yourname-contacts, PK messageId String, on-demand.
  2. SNS topic yourname-contact-alerts. Email subscription → confirm in inbox.

B. IAM + Lambda

  1. Role: basic logs + zip inline (PutItem + sns:Publish on that topic).
  2. Function yourname-contact-api, Python 3.12, handler.py. Env TABLE_NAME, TOPIC_ARN. Deploy.

C. API + test

  1. HTTP API POST /contact → Lambda. CORS *. Copy API_BASE.
curl -s -X POST "$API_BASE/contact" -H 'content-type: application/json' \
  -d '{"name":"Riya","email":"riya@example.com","message":"Need AWS batch timing"}'

Expect {"ok":true,"messageId":"..."}, then email + DynamoDB row.

Cleanup

  1. Delete API, Lambda, table, SNS subscription and topic, IAM role.
  2. Remove the topic so lab mail does not keep arriving.

3. Interview

Q. Why SNS not SES here?

One alert email: SNS is enough. SES for branded bulk (sandbox).

Q. CORS why?

Browser page origin differs from API.

Q. PII?

Messages are personal — tight IAM, delete lab data.

Q. If SNS fails after PutItem?

Lab order saves first; production uses outbox/transactions.

Q. Cleanup?

API, Lambda, table, topic, role.

Try at home

  1. Add a honeypot field; reject if filled.
  2. Admin GET with API key.

In short

  1. Contact = API GW + Lambda + DynamoDB + SNS.
  2. Confirm SNS email.
  3. Validate input.
  4. Clean up.

Practice Tasks

About this scenario

Nashik Vineyards is a wine and farming business in Nashik. Meera Joshi looks after its IT and cloud work. They count money in INR and run their AWS resources in the ap-south-1 Region. In the tasks below you do real jobs for them using what this lesson teaches. All names, account IDs, IP addresses and numbers are made up for practice.

0 / 12

Easy List functions

Why: See which functions exist in this Region.

What to do: List the Lambda functions in ap-south-1.

How:
  1. Read the task and decide which AWS service it is about.
  2. Write aws, then the service name, then the operation (the action word).
  3. Add each needed flag (--name) followed by its value from the task.
  4. Flags can be in any order. Click Check answer.

Medium Invoke a function

Why: Invoke runs the function now and saves its answer in a file.

What to do: Invoke nashikvine-orders-fn and save the response to out.json.

How:
  1. Read the task and decide which AWS service it is about.
  2. Write aws, then the service name, then the operation (the action word).
  3. Add each needed flag (--name) followed by its value from the task.
  4. Flags can be in any order. Click Check answer.

Medium Trust policy for a Lambda role

Why: The trust policy says WHO may take the role.

What to do: Write a trust policy that lets lambda.amazonaws.com assume the role.

How:
  1. Start with { "Version": "2012-10-17", "Statement": [ ... ] }.
  2. In each statement write Effect, Action and Resource.
  3. Give only what the task needs (least privilege).
  4. Use double quotes and commas correctly. Click Check answer.

Medium Put an item

Why: DynamoDB JSON shows the type of each value: S for string, N for number.

What to do: Put an item into nashikvine-orders with orderId "o-101" (string) and amount 2500 (number).

How:
  1. Read the task and decide which AWS service it is about.
  2. Write aws, then the service name, then the operation (the action word).
  3. Add each needed flag (--name) followed by its value from the task.
  4. Flags can be in any order. Click Check answer.

Medium Change timeout and memory

Why: More memory also gives more CPU; timeout stops runaway runs.

What to do: Set nashikvine-orders-fn to timeout 30 seconds and memory 512 MB.

How:
  1. Read the task and decide which AWS service it is about.
  2. Write aws, then the service name, then the operation (the action word).
  3. Add each needed flag (--name) followed by its value from the task.
  4. Flags can be in any order. Click Check answer.

Medium Let a function write logs

Why: Without these actions, Lambda logs never appear in CloudWatch.

What to do: Allow logs:CreateLogGroup, logs:CreateLogStream, logs:PutLogEvents on arn:aws:logs:*:*:* only.

How:
  1. Start with { "Version": "2012-10-17", "Statement": [ ... ] }.
  2. In each statement write Effect, Action and Resource.
  3. Give only what the task needs (least privilege).
  4. Use double quotes and commas correctly. Click Check answer.

Hard Let S3 call your function

Why: A resource-based permission is needed before S3 can invoke the function.

What to do: Add permission statement s3invoke to nashikvine-orders-fn so s3.amazonaws.com can call lambda:InvokeFunction from bucket arn:aws:s3:::nashikvine-uploads.

How:
  1. Read the task and decide which AWS service it is about.
  2. Write aws, then the service name, then the operation (the action word).
  3. Add each needed flag (--name) followed by its value from the task.
  4. Flags can be in any order. Click Check answer.

Hard Create a Lambda function

Why: Lambda needs the code zip, a runtime, a handler name and an execution role.

What to do: Create function nashikvine-orders-fn: runtime python3.12, handler app.handler, role arn:aws:iam::107079156755:role/lambda-basic, code in function.zip.

How:
  1. Read the task and decide which AWS service it is about.
  2. Write aws, then the service name, then the operation (the action word).
  3. Add each needed flag (--name) followed by its value from the task.
  4. Flags can be in any order. Click Check answer.

Hard Set environment variables

Why: Keep settings like table names out of the code.

What to do: Set the environment variable TABLE=nashikvine-orders on nashikvine-orders-fn.

How:
  1. Read the task and decide which AWS service it is about.
  2. Write aws, then the service name, then the operation (the action word).
  3. Add each needed flag (--name) followed by its value from the task.
  4. Flags can be in any order. Click Check answer.

Hard Invoke with a JSON payload

Why: In CLI v2, raw JSON needs --cli-binary-format raw-in-base64-out.

What to do: Invoke nashikvine-orders-fn with payload {"orderId":"o-101"} (raw JSON) and save the reply in out.json.

How:
  1. Read the task and decide which AWS service it is about.
  2. Write aws, then the service name, then the operation (the action word).
  3. Add each needed flag (--name) followed by its value from the task.
  4. Flags can be in any order. Click Check answer.

Hard Lambda GB-seconds

Why: Lambda bills memory × time.

What to do: 1,000,000 invocations, 512 MB memory, 200 ms each. How many GB-seconds?

How:
  1. Write down the numbers the task gives you.
  2. Work it out step by step on paper.
  3. Type only the final answer in the box.
  4. Click Check answer.

Hard Connect an SQS queue to Lambda

Why: An event source mapping makes Lambda poll the queue and process messages in batches.

What to do: Create an event source mapping from queue arn:aws:sqs:ap-south-1:107079156755:nashikvine-orders to nashikvine-orders-fn with batch size 10.

How:
  1. Read the task and decide which AWS service it is about.
  2. Write aws, then the service name, then the operation (the action word).
  3. Add each needed flag (--name) followed by its value from the task.
  4. Flags can be in any order. Click Check answer.

Revision, comparison and interview cards

Revise this lesson in a few minutes. Save the cards on your phone or download them as PNG files. The QR code on each card opens this lesson.

Revision card: Contact form API with SNS. Every business site has a Contact Us box. Email-only forms lose messages; you want a saved row plus an alert. API Gateway accepts POST. Lambda writes the message to DynamoDB and publishes to an SNS topic that emails you. Create table (PK messageId), SNS topic + email subscription, Lambda with PutItem + sns:Publish, HTTP API POST /contact. curl POST {"name":"Ravi","email":"a@b.com","msg":"Hi"} → 201, DynamoDB row, and an email in your inbox.
Revision card: Contact form API with SNS · Download PNG · Open card page
Revision card: Why SNS for the alert?. Hard-coding SMTP in Lambda means passwords, ports, and spam filters. You only need “email me when someone writes”. Amazon SNS is a pub/sub service. Subscribe your email to a topic; Lambda publishes once; SNS delivers. Create topic → Create subscription Email → confirm the link → put TOPIC_ARN in Lambda env → sns:Publish in IAM. One publish can later also SMS or hit another Lambda without changing the contact handler.
Revision card: Why SNS for the alert? · Download PNG · Open card page
Revision card: Save first, then notify. If email fails and you never saved the message, the lead is gone forever. Write PutItem to DynamoDB first (messageId, name, email, msg, createdAt). Then Publish to SNS. Return 201 with the id. Handler: uuid messageId → put_item → sns.publish Subject Contact body → return JSON. SNS outage still leaves the row in DynamoDB so you can follow up from the table view.
Revision card: Save first, then notify · Download PNG · Open card page
Comparison: DynamoDB then SNS vs SNS only. DynamoDB then SNS: Message saved even if email fails. SNS only: If publish fails, the lead may be gone.
Comparison: DynamoDB then SNS vs SNS only · Download PNG · Open card page
Interview card: Save to DynamoDB before SNS or after?. Save first. If publish fails you still have the lead. Notify-only with no store loses messages during email outages. PutItem then sns.publish; log publish errors but still return 201 with messageId.
Interview card: Save to DynamoDB before SNS or after? · Download PNG · Open card page
Interview card: Why SNS instead of SMTP from Lambda?. No mail server credentials in the function; SNS handles delivery to subscribed emails. Later you can add SMS or another Lambda subscriber without rewriting the form handler. Topic ARN in env; IAM sns:Publish on that ARN only.
Interview card: Why SNS instead of SMTP from Lambda? · Download PNG · Open card page

More cards: Ravi Sir's Cards.