The Tool Desk
Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Week 2 of the Cloud Resume Challenge adds a visitor counter to your resume site. The page calls an API, API Gateway passes the request to a Lambda function, and that function reads and updates a counter stored in DynamoDB. The browser never talks to DynamoDB directly. This guide walks through that backend, separates what the challenge requires from the design choices you have to make yourself, and flags the points where people most often get stuck.
What the challenge requires and what it leaves to you
The official Cloud Resume Challenge page, published by AWS, asks for three things in this step: the resume webpage must display a visitor count, a backend must retrieve and update that value, and the backend resources should be managed as infrastructure as code. It recommends DynamoDB for storage and API Gateway with Lambda for the backend. It also says not to connect browser JavaScript directly to DynamoDB, and it does not require the console to be used for building resources.
As an Amazon Associate I earn from qualifying purchases.
The challenge does not specify the following, so each one is a decision you make and should be able to explain:
- Whether you use an HTTP API or a REST API in API Gateway
- The route path, HTTP method, and JSON response shape
- The DynamoDB table name, key schema, and item layout
- What a “visit” means for the counter
- The exact CORS policy
- Whether you use AWS SAM or Terraform
The choices below are the ones used in this walkthrough. They are a reasonable starting point, not the only correct answer.
#1 Best Overall
- Includes Raspberry Pi 5 with 2.4Ghz 64-bit quad-core CPU (8GB RAM)
- Includes 128GB Micro SD Card pre-loaded with 64-bit Raspberry Pi OS, USB MicroSD Card Reader
- CanaKit Turbine Black Case for the Raspberry Pi 5
- CanaKit Low Noise Bearing System Fan
- Mega Heat Sink - Black Anodized
How the pieces fit together
The request path is:
Resume page JavaScript → API Gateway → Lambda → DynamoDB
Each service has one job:
- The page script sends an HTTP request when the page loads and writes the returned number into the HTML.
- API Gateway exposes a public HTTPS endpoint, matches the request to a route, and invokes the integration behind it. It also handles CORS headers if you configure them.
- Lambda runs your code. For this project, the code increments the counter and returns the new value.
- DynamoDB stores the counter as an item, so the value survives between invocations and is not held in memory by the function.
The response travels the same path in reverse. If any hop fails, the page should still render, which is covered in the failure section below.
Step 1: Design the data model and define the counter
Start by deciding what the number means, because the code and the table design follow from that decision.
Rank #2
- Includes Raspberry Pi 5 16GB with 2.4Ghz 64-bit quad-core CPU (16GB RAM)
- Includes 128GB Micro SD Card pre-loaded with 64-bit Raspberry Pi OS, USB MicroSD Card Reader
- CanaKit Turbine Black Case for the Raspberry Pi 5
- CanaKit Low Noise Bearing System Fan
- Mega Heat Sink - Black Anodized
| What you count | How it is implemented | What the number honestly means |
|---|---|---|
| Requests to the endpoint | Increment once per API call, with no identity check | Page loads and reloads, including bots and your own testing |
| Unique visitors | Requires an identifier per visitor (for example a cookie or hashed client detail) and a record of seen identifiers | Closer to distinct browsers, but still not exact people; adds privacy and storage considerations |
For the first Week 2 build, a request counter is the simpler choice. Label it as a page-view or request counter on the page, not as “unique visitors,” unless you have implemented deduplication.
Use a single item with a simple partition key. For example, a table called visitor-counter with a string partition key named id, and one item whose id is visits and which holds a numeric attribute named count. A single-item design is fine for a resume site and keeps the access pattern trivial.
Keep the table in the same AWS region as the Lambda function. The region is part of the endpoint and of the resource names, and mismatches are a common source of confusion later.
Rank #3
- Pi5 8GB Pack: RasTech Pi 5 8GB kit includes 1 x Pi5 8GB board ,1 x 64GB Card, 2 x Card Readers,1 x Active Cooler,1 x Case for Pi5, 2 x 4K Micro HD Out Cable,1 x GaN 27W 5A USB-C Power supply,1 x Screwdriver and 1 x instructions.
- Pi5 8GB Board: The Pi5 board is equipped with a 64-bit quad-core Arm Cortex-A76 processor running at 2.4GHz and an 800MHz VideoCore VII GPU with support for OpenGL ES 3.1 and Vulkan 1.2, which delivers a significant increase in graphics performance. Dual HD Out 4Kp60 display outputs and a built-in dual 4-channel MIPI camera/display transceiver provide state-of-the-art camera support. The Pi 5 offers a 2-3 times increase in CPU performance compare to Pi4.
- Important Graphics Features: Equipped with an 800MHz VideoCore VII GPU and providing better graphics performance, suitable for multimedia applications,gaming,and graphics intensive tasks.Provides 1 UART interface,1 card slot that supports high-speed operation, 2 USB. 3 0.5 ports that support synchronous 0Gbps operation,2 USB 2.0 port ports,2 4Kp60 display outputs that support HDR.Built-in dedicated dual 4-channel 1Gbps MIPI DSI/CSI connectors,triple the total bandwidth.
- Cooling Kit for Pi 5: Compatible with Active Cooler for Raspberry Pi5, It can provide Pi 5 board with better cooling effect in using. The Case can accurately access usb-c power jack,Micro HD Out ports, usb ports, Ethernet jack, card slot, power button, 4-lane MIPI DSI/CSI connectors and so on, and it also supports installation of cooling fan.
- 64GB Card Kit and GaN 27W USB-C Power Supply: With extra 64GB card to store more files and card readers for multiple medium, keep better performance for Raspberry Pi 5, 27W USB C Power Supply is Compatible with Pi5 8GB, offers a variety of output voltage options, including 5.1V at 5A, 9.0V at 3.0A, 12.0V at 2.25A, and 15.0V at 1.8A, providing for different device requirements.
Step 2: Write the Lambda function
The challenge recommends Python with boto3, which is the AWS SDK for Python. The handler below is one illustrative pattern, not a required solution. It reads the table name from an environment variable, increments the counter atomically, and returns JSON.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
import json
import os
import boto3
table = boto3.resource('dynamodb').Table(os.environ['TABLE_NAME'])
def handler(event, context):
result = table.update_item(
Key={'id': 'visits'},
UpdateExpression='ADD #c :inc',
ExpressionAttributeNames={'#c': 'count'},
ExpressionAttributeValues={':inc': 1},
ReturnValues='UPDATED_NEW'
)
count = int(result['Attributes']['count'])
return {
'statusCode': 200,
'headers': {'Content-Type': 'application/json'},
'body': json.dumps({'count': count})
}
Why this shape matters:
- Atomic increment. A read-then-write approach (get the item, add one in code, put it back) can lose increments when two requests arrive at the same moment. An
ADDupdate expression asks DynamoDB to do the addition on the server side. Confirm the current behavior ofUpdateItemandADDin the DynamoDB developer guide before you rely on it for accuracy claims. - The first call creates the item.
ADDcreates the attribute if it does not exist, starting from zero. You do not need a separate seeding step for this pattern. - Environment variable for the table name. Keeping the name out of code makes the function reusable across environments and keeps the infrastructure template as the single source of names.
Step 3: Choose the API type and route
The AWS API Gateway tutorial for building a serverless CRUD API uses an HTTP API, creates a Lambda function and a DynamoDB table, adds routes, and tests the result. It is a general example, not a recipe for this challenge. It also recommends separate functions per route as a best practice, while using a single function to keep the tutorial simple. For a one-route counter, a single function is reasonable.
For this build:
- Use an HTTP API, which is the lighter option for a simple Lambda proxy integration. Check current feature differences against REST APIs in the API Gateway documentation if you need features such as usage plans or request validation.
- Expose GET /visitors (or a similar route). The browser sends a GET request and reads the JSON response.
- Return a body in the form
{"count": 42}, so the front end reads one field.
Step 4: Set least-privilege permissions
The Lambda execution role needs the basic logging permissions that AWS provides through its managed Lambda execution policy, plus one DynamoDB action on one table. For this function, the only data action required is dynamodb:UpdateItem on the table’s ARN. Do not attach a full-access DynamoDB policy to make an error go away. Broad grants work, but they hide the real permission problem and are not a good habit to build in a portfolio project. Write the policy against the table resource, then check CloudWatch logs if the function still fails.
Rank #4
- 𝗦𝗲𝗮𝗺𝗹𝗲𝘀𝘀 𝗦𝗲𝘁𝘂𝗽 𝘄𝗶𝘁𝗵 𝗣𝗿𝗲-𝗜𝗻𝘀𝘁𝗮𝗹𝗹𝗲𝗱 𝗢𝗦: Start creating right out of the box—our kit arrives with Raspberry Pi OS already on the microSD card, saving you time and effort from day one.
- 𝗘𝘃𝗲𝗿𝘆𝘁𝗵𝗶𝗻𝗴 𝗬𝗼𝘂 𝗡𝗲𝗲𝗱, 𝗔𝗹𝗹 𝗶𝗻 𝗢𝗻𝗲 𝗕𝗼𝘅: From the case to the power supply and a generous microSD card, we’ve bundled every essential so you can skip the extra shopping and focus on building your dream project.
- 𝗔𝗱𝘃𝗮𝗻𝗰𝗲𝗱 𝗖𝗼𝗼𝗹𝗶𝗻𝗴 𝗳𝗼𝗿 𝗣𝗲𝗮𝗸 𝗣𝗲𝗿𝗳𝗼𝗿𝗺𝗮𝗻𝗰𝗲: Enjoy smooth, reliable operation as our whisper-quiet fan and heat sinks work together to keep your Pi running cool—even during intensive tasks.
- 𝗩𝗲𝗿𝘀𝗮𝘁𝗶𝗹𝗶𝘁𝘆 𝗳𝗼𝗿 𝗔𝗻𝘆 𝗣𝗿𝗼𝗷𝗲𝗰𝘁: Whether it’s coding lessons, retro gaming, smart home setups, or robotics experiments, our kit powers unlimited possibilities, letting you tailor your Pi adventure to your passion.
- 𝗚𝗹𝗼𝗯𝗮𝗹𝗹𝘆 𝗧𝗿𝘂𝘀𝘁𝗲𝗱 𝗯𝘆 𝗘𝗻𝘁𝗵𝘂𝘀𝗶𝗮𝘀𝘁𝘀 & 𝗘𝗱𝘂𝗰𝗮𝘁𝗼𝗿𝘀: Join a worldwide community of hobbyists, teachers, and first-time makers who rely on Vilros for top-tier quality, comprehensive support, and ongoing inspiration.
Step 5: Handle CORS for the real website origin
Your resume page is served from one origin, such as a CloudFront distribution or a static-site host, and the API lives on another origin (the API Gateway domain). A browser blocks the page from reading the response unless the API says that origin is allowed. This is the CORS check.
- Configure CORS in the API definition for the exact frontend origin, for example
https://your-resume-domain.example, and allow only the methods and headers you use. - Avoid a wildcard origin as a production default. AWS’s current general tutorial advises restricting CORS origins in production. A wildcard may be acceptable for a short local test, but tighten it before you finish.
- Make sure the Lambda response includes the matching headers if your integration returns them directly, and that the API’s CORS settings and the function’s headers do not contradict each other.
The challenge does not give a complete CORS configuration, so verify the exact settings against the current API Gateway documentation for the API type you chose.
Step 6: Deploy with infrastructure as code
The challenge asks you to manage the table, API, function, and permissions as code rather than configuring each one in the console. It recommends AWS SAM and accepts Terraform as an alternative. Both are valid.
Best Value
- Includes Raspberry Pi 4 4GB Model B with 1.5GHz 64-bit quad-core CPU (4GB RAM)
- Includes Pre-Loaded 32GB EVO+ Micro SD Card (Class 10), USB MicroSD Card Reader
- CanaKit Premium High-Gloss Raspberry Pi 4 Case with Integrated Fan Mount, CanaKit Low Noise Bearing System Fan
- CanaKit 3.5A USB-C Raspberry Pi 4 Power Supply (US Plug) with Noise Filter, Set of Heat Sinks, Display Cable - 6 foot (Supports up to 4K60p)
- CanaKit USB-C PiSwitch (On/Off Power Switch for Raspberry Pi 4)
| Tool | Strengths for this project | Trade-offs |
|---|---|---|
| AWS SAM | AWS-specific template with short syntax for Lambda, API Gateway, and DynamoDB; the challenge recommends it | Works mainly within AWS; you learn an AWS-specific template format |
| Terraform | Reusable skill across clouds and teams; explicit resource graph | More verbose for a small serverless stack; you manage provider and state configuration |
If you choose SAM, the usual workflow is:
- Define the table, function, HTTP API, and CORS settings in
template.yaml. - Run
sam buildto package the function. - Run
sam deploy --guidedthe first time, and choose the region that matches your table. - Copy the API endpoint from the stack outputs and place it in your page’s script.
Check the current SAM documentation for exact flags and template syntax, since these change over time.
Step 7: Connect the page and test
In the resume page script, call the endpoint and write the number into the page. Show a fallback message if the request fails, so the page remains readable:
const COUNTER_URL = 'https://your-api-id.execute-api.your-region.amazonaws.com/visitors';
async function showVisitorCount() {
const el = document.getElementById('visitor-count');
try {
const res = await fetch(COUNTER_URL);
if (!res.ok) throw new Error('HTTP ' + res.status);
const data = await res.json();
el.textContent = data.count;
} catch (err) {
el.textContent = 'unavailable';
}
}
showVisitorCount();
Test in three layers, in this order:
- Direct endpoint: call the URL with curl or a browser address bar. You should see the JSON body and the count should increase on each call.
- Table: open the table in the DynamoDB console and confirm the item
visitshas the expectedcount. - Browser: load the deployed page and check the developer tools network tab for the request and its response headers.
Common failure modes
- CORS error in the browser console. The endpoint responded, but the origin is not allowed. Compare the page’s exact origin, including scheme and port, with the origin in the API’s CORS configuration.
- AccessDeniedException in function logs. The execution role lacks
dynamodb:UpdateItemon the table ARN. Check the table name and region in the policy. - Counter never increases or returns an error. The table name environment variable is missing or misspelled, or the function points at a table in another region.
- Endpoint returns 404. The route in the page does not match the route in the API definition, or you are calling the stage URL without the stage path.
- Counter jumps unexpectedly. Your own reloads, browser prefetching, and bots count under a request-counter design. This is expected behavior, not a bug.
To inspect failures, open the Lambda function in the console, find the Monitor view, and open the CloudWatch logs for the function. Console labels move around, so verify the current path before following it step by step.
Costs, limits, and what this build does not prove
AWS’s tutorial states that its own exercise can be completed within the AWS Free Tier. Your actual cost depends on account eligibility, region, and request volume, so do not assume it is free indefinitely. Check the AWS Free Tier page and the pricing pages for each service before you rely on it.
This build counts requests. It does not show unique visitors, and it does not guard against bots. The number is a useful signal for a personal site, not a traffic measurement you should present to an employer as audience data.
Quick Recap
Learning resources
- The Cloud Resume Challenge page on AWS for the official requirements.
- The AWS API Gateway tutorial for building a serverless CRUD API, as a general reference for HTTP APIs, Lambda integration, and DynamoDB.
- The AWS Lambda getting-started guide for the service basics.
- The Cloud Resume Challenge book, which AWS links to from the challenge page as further learning. Search for it by that title, since listings, editions, and availability change.
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




