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

Project: Build a URL Shortener with Lambda, API Gateway and DynamoDB (Source Code)

Like bit.ly or WhatsApp short links: a tiny code opens a long URL. Build it with API Gateway, Lambda and DynamoDB — same stack as the Notes project. Download the zip, deploy in ap-south-1, test redirects, then clean up.

What you'll learn in this chapter

  • Design shortCode PK and click counter
  • Create table, IAM, Lambda, HTTP API
  • POST /shorten and GET /{code} redirect
  • Verify with curl and clean up

1. Everyday example first

Why do we need this?

Instagram bio and Flipkart share links cannot paste a huge URL. A shortener stores the long URL, returns a 7-character code, and on each visit redirects and counts clicks. No EC2.

What is it?

HTTP API to Lambda to DynamoDB table with PK shortCode, attributes longUrl and clicks. POST creates. GET returns 302 and ADD clicks.

Request pathClientPOST /shortenAPI Gateway HTTP APILambdaPutItemClientGET /Ab12XyZLambdaGetItem + ADD clicks302
Same idea as the Notes API lab.

Download: url-shortener-app.zip — Python handler.py (boto3 built-in), sample IAM.

2. Architecture

PieceServiceWhy
APIAPI Gateway HTTP APIHTTPS + CORS
LogicLambda Python 3.12boto3 included
DataDynamoDB on-demandKeyed by shortCode

3. Lab: deploy click by click

How to do it (step by step)

Region ap-south-1. Replace yourname.

A. DynamoDB

  1. Create table yourname-urls. PK shortCode (String). On-demand. No sort key.
  2. Wait until Active.

B. IAM role

  1. Create role for Lambda. Attach AWSLambdaBasicExecutionRole. Name yourname-urls-role.
  2. Inline policy from the zip: PutItem, GetItem, UpdateItem on that table only. Replace ACCOUNT_ID.

C. Lambda

  1. Create function yourname-urls-api, Runtime Python 3.12, existing role.
  2. Paste lambda/handler.py. Handler handler.lambda_handler.
  3. Env TABLE_NAME=yourname-urls. Memory 256 MB, timeout 10 s. Deploy.

D. HTTP API

  1. Create HTTP API yourname-urls-http, integrate the Lambda.
  2. Routes: POST /shorten, GET /{code}.
  3. CORS origin *, methods GET,POST,OPTIONS.
  4. Copy Invoke URL as API_BASE. Set Lambda env BASE_URL=API_BASE (no slash). Deploy again.

E. Test

curl -s -X POST "$API_BASE/shorten" -H 'content-type: application/json' \
  -d '{"url":"https://ravindrabagale.com/aws/"}'
curl -sI "$API_BASE/YOURCODE" | head -5

Expect 201 JSON with shortCode, then 302 Location to the long URL. DynamoDB clicks should be at least 1.

Cleanup

  1. Delete HTTP API, Lambda, DynamoDB table, IAM role.
  2. Check Billing for tiny / free-tier charges only.

4. Interview angles

Q. Why 302 not 200 with URL in body?

Browsers follow Location; that is a shortener.

Q. Why ADD clicks?

Atomic under concurrent redirects.

Q. GetItem vs Scan for redirect?

Always GetItem by PK.

Q. Custom domain?

ACM + API custom domain or CloudFront.

Q. Cleanup list?

API, Lambda, table, role.

Try at home

  1. Add GET /stats/{code} returning clicks without redirect.
  2. Allow only https URLs.

In short

  1. Shortener = HTTP API + Lambda + DynamoDB.
  2. POST creates; GET redirects and counts.
  3. Least-privilege IAM.
  4. Clean up.

Practice Tasks

About this scenario

Lisboa Tiles is a ceramic tiles business in Lisbon. João Silva looks after its IT and cloud work. They count money in EUR and run their AWS resources in the eu-west-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 eu-west-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 lisboatiles-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 lisboatiles-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 lisboatiles-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 lisboatiles-orders-fn so s3.amazonaws.com can call lambda:InvokeFunction from bucket arn:aws:s3:::lisboatiles-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 Quick-create an HTTP API for Lambda

Why: Quick create builds an HTTP API, a default route and stage pointing at your function.

What to do: Create an HTTP API named lisboatiles-api whose target is arn:aws:lambda:eu-west-1:101273714098:function:lisboatiles-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 Create a Lambda function

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

What to do: Create function lisboatiles-orders-fn: runtime python3.12, handler app.handler, role arn:aws:iam::101273714098: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=lisboatiles-orders on lisboatiles-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 lisboatiles-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.

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: What is a URL shortener?. Instagram bios and Flipkart share links cannot paste a huge URL. People need a tiny code that opens the long page. A URL shortener stores a long URL behind a short code (like Ab12XyZ). Visiting the short link redirects to the long URL and can count clicks. Build it with API Gateway (HTTPS), Lambda (logic), and DynamoDB (shortCode → longUrl, clicks). No always-on EC2. POST {"url":"https://ravindrabagale.com/aws/"} returns shortCode Ab12XyZ. GET /Ab12XyZ returns HTTP 302 to that long URL.
Revision card: What is a URL shortener? · Download PNG · Open card page
Revision card: URL shortener architecture. Pieces must fit: front door, compute, and keyed storage for millions of codes. HTTP API routes → one Lambda → DynamoDB table with partition key shortCode (String). Attributes: longUrl, clicks. Create table on-demand, IAM role with Put/Get/UpdateItem, paste handler, add POST /shorten and GET /{code}, set TABLE_NAME and BASE_URL. curl POST /shorten then curl -I /CODE shows Location: https://ravindrabagale.com/aws/ and clicks becomes 1.
Revision card: URL shortener architecture · Download PNG · Open card page
Revision card: Why 302 and ADD clicks?. Returning 200 with the URL in JSON forces every client to invent redirect logic. Browsers already follow Location. HTTP 302 Found with a Location header is the classic shortener response. ADD on clicks is an atomic DynamoDB increment under concurrent hits. In Lambda: GetItem by shortCode → UpdateItem ADD clicks :1 → return statusCode 302 and headers Location = longUrl. Two phones open /Ab12XyZ at once; both redirect and clicks becomes 2, not a lost update.
Revision card: Why 302 and ADD clicks? · Download PNG · Open card page
Revision card: Clean up the shortener lab. Forgotten HTTP APIs and DynamoDB tables clutter the account and can surprise you on the bill. Delete in order: API Gateway HTTP API, Lambda function, DynamoDB table, IAM role (and inline policy). API Gateway console › delete API; Lambda › delete; DynamoDB › delete table; IAM › delete role. Confirm Billing free-tier noise only. After cleanup, curl to the old invoke URL fails; Cost Explorer shows near-zero for the lab.
Revision card: Clean up the shortener lab · Download PNG · Open card page
Comparison: JSON 200 with URL vs HTTP 302 redirect. JSON 200 with URL: Client reads JSON and navigates itself. HTTP 302 redirect: Browser follows Location automatically.
Comparison: JSON 200 with URL vs HTTP 302 redirect · Download PNG · Open card page
Interview card: Why return 302 instead of 200 with the long URL?. Browsers automatically follow the Location header. That is what users expect from a short link. A JSON 200 forces every client (browser, WhatsApp preview, curl scripts) to special-case your API. Lambda returns statusCode 302 and headers Location = longUrl from DynamoDB GetItem.
Interview card: Why return 302 instead of 200 with the long URL? · Download PNG · Open card page
Interview card: Why ADD clicks instead of read-modify-write?. Two redirects at once can both read clicks=5 and both write 6 — one click lost. UpdateItem ADD is atomic on the server for that attribute. UpdateExpression SET … ADD clicks :one with :one = 1 on every redirect.
Interview card: Why ADD clicks instead of read-modify-write? · Download PNG · Open card page
Interview card: GetItem or Scan to resolve a short code?. Always GetItem by partition key shortCode. Scan would read the whole table. Shortener traffic is a classic single-key lookup pattern. PK shortCode String; GetItem Key={shortCode: code} in under 10 ms typically.
Interview card: GetItem or Scan to resolve a short code? · Download PNG · Open card page

More cards: Ravi Sir's Cards.