Build a Serverless URL Shortener API
Build a live REST API on AWS using Lambda, DynamoDB, and API Gateway.
Introduction
30 Second Summary
Every time you click a shortened link, a system somewhere instantly looks up that short code and sends you to the right page. Behind the scenes, this runs on serverless infrastructure that costs almost nothing and scales to millions of clicks without anyone managing a server.
In this project, you will build a URL Shortener API that runs entirely on AWS serverless services. You will create short URLs, retrieve them, list all stored URLs, and delete them via HTTP requests from anywhere.
What You'll Build
A serverless REST API on AWS that accepts long URLs, returns shortened versions, and exposes four routes you can call from any machine using curl.
By the end of this project, you'll have:
- A DynamoDB table storing URL mappings with a partition key design.
- A Lambda function written in Node.js that handles all CRUD operations using AWS SDK v3.
- A live HTTP API with four routes exposed via API Gateway that you can call from anywhere.
- Secret Mission: Add click tracking that counts how many times each short URL is accessed.
Are there any prerequisites?
No prior AWS experience is needed. This guide walks you through creating an AWS account, setting up IAM, and building every resource from scratch in the AWS Console.
Set Up Your AWS Account
To build your URL shortener API, you need access to AWS cloud services. AWS provides the serverless infrastructure that will host your API with zero servers to manage.
In this step, you will create an AWS account, set up a secure user for development, and configure your console region.
In this step, get ready to:
- Create an AWS Free Tier account.
- Create an IAM user for secure development access.
- Set your console region to US East (N. Virginia).
Create an AWS Free Tier account
AWS Free Tier gives new accounts up to $200 in credits over 6 months. You will not be charged for this project as long as you stay on the Free plan.
- Open https://aws.amazon.com/free/ in your browser.
- Click Create a free account.
- Enter your email address and an account name, then click Verify email address.
- Check your email for a verification code, enter it, and click Verify.
- Create a root user password and click Continue.
- Choose Personal as your account type and fill in your contact information.
- Accept the AWS Customer Agreement and click Continue.
- Enter a payment method on the Billing information page, then click Verify and Add.
- Verify your phone number using SMS or a voice call, enter the PIN, and click Continue.
- On the support plan page, select Basic Support (free).
- Select the Free plan when prompted to choose between Free and Paid.
- Click Complete sign up.
Will I be charged?
No. A payment method is required to create the account, but you will not be charged while on the Free plan. The account closes on its own after 6 months or when credits run out.
Lambda and DynamoDB (the services you will use in this project) are Always Free tier services, meaning they remain free even after the 6-month period ends.
- Wait for the activation confirmation email from AWS. This usually arrives within a few minutes but can take up to 24 hours.
- Once activated, sign in to the AWS Management Console using the email and password you just created.
Not seeing the activation email?
Check your spam or junk folder. AWS sends the confirmation from a no-reply address that some email providers filter. If it has been more than 24 hours, contact AWS Support.
help me troubleshoot my AWS account activation
Create an IAM user for development
You just signed in with your root account. The root account has unrestricted access to everything in your AWS account, so it is best practice to create a separate IAM user for day-to-day development work.
- In the search bar at the top of the AWS Console, type IAM and select IAM from the results.
- In the left navigation pane, click Users.
- Click Create user.
- For User name, enter a name like admin-dev.
- Check the box for Provide user access to the AWS Management Console.
- Select I want to create an IAM user if prompted.
- Choose Custom password and enter a password you will remember.
- Uncheck Users must create a new password at next sign-in (you are the only user).
- Click Next.
- On the Set permissions page, select Attach policies directly.
- In the search box, type AdministratorAccess and check the box next to the AdministratorAccess policy.
- Click Next.
- Review the details and click Create user.
What is IAM?
IAM (Identity and Access Management) lets you create separate users with specific permissions for your AWS account. Using an IAM user for daily work keeps your root credentials safe.
The AdministratorAccess policy grants full access to all AWS services. This is appropriate for a learning project where you are the only user.
- Note your sign-in URL shown on the success page (or find it later on the IAM dashboard).
- Sign out of the root account by clicking your account name in the top-right corner, then selecting Sign out.
- Sign back in using the IAM user sign-in URL, your new username, and password.
Cannot find the IAM sign-in URL?
Your IAM sign-in URL follows this pattern: https://YOUR-ACCOUNT-ID.signin.aws.amazon.com/console. You can find your account ID on the IAM dashboard or by clicking your account name in the top-right of the console.
help me find my IAM sign-in URL
Set your region
AWS runs data centers in multiple regions around the world. All resources you create need to be in the same region so they can communicate with each other.
- Look at the top-right corner of the console, next to your username. You will see a region name displayed.
- Click the region name to open the region selector dropdown.
- Select US East (N. Virginia) us-east-1.
Why us-east-1?
US East (N. Virginia) is the default region for most AWS tutorials and has all services available. Using a consistent region avoids confusion when locating your resources later.
Confirm that the region display in the top-right now shows N. Virginia.
Your AWS account is ready to go. Next up, you will create the DynamoDB table that stores your shortened URLs.
Create the DynamoDB Table
Your AWS account is set up and secured with an IAM user. Now you need a database to store your URL mappings.
Every URL shortener needs a place to remember which short codes point to which long URLs. DynamoDB is a NoSQL database service from AWS that stores data as key-value pairs. It is perfect for this project because looking up a short code is a simple key lookup.
In this step, get ready to:
- Create a DynamoDB table called url-shortener-links.
- Verify the table status is Active and ready to store data.
Create the URL storage table
Your URL shortener needs a table where each row maps a short code (like abc123) to a full URL. You will create this table in the DynamoDB console.
- In the AWS Console search bar at the top, type DynamoDB and select the DynamoDB service from the results.
- Click Create table.
- For Table name, enter url-shortener-links.
- For Partition key, enter shortCode.
- Make sure the data type dropdown next to the partition key is set to String.
- Leave all other settings as defaults (under Table settings, keep Default settings selected).
- Click Create table.
What is a partition key?
A partition key is the primary lookup value for your table. Every item in the table must have a unique partition key.
For your URL shortener, the partition key is shortCode. When someone visits a short URL, DynamoDB uses the short code to instantly find the matching long URL. Think of it like a dictionary index where the short code is the word and the original URL is the definition.
Why use default settings?
The default settings use provisioned capacity with auto scaling. This falls within the DynamoDB Always Free tier, which gives you 25 Read Capacity Units (RCU) and 25 Write Capacity Units (WCU) per month at no cost.
For a learning project like this, you will never come close to those limits.
Getting a permissions error?
Make sure you are signed in as your IAM user with AdministratorAccess, not the root account. Check the top-right corner of the console to confirm your username.
Also confirm your region is still set to US East (N. Virginia) us-east-1 in the top-right dropdown.
Help me troubleshoot this DynamoDB permissions error.
Verify the table is active
DynamoDB takes a few seconds to create your table. You need to confirm it is active before moving on.
- Wait for the table status to change from Creating to Active. This usually takes about 5-10 seconds.
- Click the table name url-shortener-links to open its details page.
- Click Explore table items to confirm the table is empty and ready to receive data.
What should I see?
The Explore table items view should show an empty table with no items returned. This confirms DynamoDB is ready to accept your URL mappings in the next step.
Table stuck on Creating?
If the status does not change to Active after 30 seconds, click the refresh icon in the tables list. If it remains stuck, check that you did not accidentally add a sort key or global secondary index, which can slow down creation.
Help me figure out why my DynamoDB table is not becoming Active.
Your database is live and waiting for data. Next up, you will create the Lambda function that reads and writes URL mappings to this table.
Create the Lambda Function
Your DynamoDB table is ready to store URL mappings. Now you need the compute layer that reads and writes to that table.
AWS Lambda lets you run code without provisioning or managing servers. You'll create a single Lambda function that handles all four CRUD operations (create, read, list, delete) for your URL shortener.
In this step, get ready to:
- Create a Lambda function with DynamoDB permissions.
- Write the CRUD handler code in Node.js.
- Test the function with a simulated API request.
Create the function in the Lambda console
- Search for Lambda in the top search bar of the AWS Management Console and open the Lambda console.
- Click Create function.
- Leave Author from scratch selected.
- For Function name, enter url-shortener-function.
- For Runtime, choose Node.js 22.x.
- Expand the Change default execution role section under Permissions.
- Select Create a new role from AWS policy templates.
- For Role name, enter url-shortener-role.
- For Policy templates, search for and choose Simple microservice permissions.
- Click Create function.
What is Simple microservice permissions?
This is an AWS policy template that grants your Lambda function permission to interact with DynamoDB. It covers all the operations you'll need: putting items, getting items, scanning, and deleting.
Without this, your function would fail every time it tries to read or write to your url-shortener-links table.
You should see a success banner confirming your function was created. The console opens your new function's configuration page.
Don't see the success banner?
Make sure your function name uses only lowercase letters, numbers, and hyphens. Also confirm you selected a policy template before clicking Create function.
help me troubleshoot why my Lambda function failed to create
Write the Lambda function code
Lambda created a default index.mjs file for you. You'll replace it with the full URL shortener handler that processes create, read, list, and delete requests.
- In your function's page, click the Code tab.
- Open index.mjs in the built-in code editor.
- Select all the existing code and delete it.
- Paste the following code into the editor:
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
import {
DynamoDBDocumentClient,
ScanCommand,
PutCommand,
GetCommand,
DeleteCommand,
} from "@aws-sdk/lib-dynamodb";
// Create a DynamoDB client and document client for simpler data handling
const client = new DynamoDBClient({});
const dynamo = DynamoDBDocumentClient.from(client);
const tableName = "url-shortener-links";
// Generate a random 6-character code for the short URL
function generateShortCode() {
const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
let result = "";
for (let i = 0; i < 6; i++) {
result += chars.charAt(Math.floor(Math.random() * chars.length));
}
return result;
}
export const handler = async (event) => {
let body;
let statusCode = 200;
const headers = {
"Content-Type": "application/json",
};
try {
// Route requests based on the HTTP method and path
switch (event.routeKey) {
case "POST /urls":
// Create a new short URL
const requestJSON = JSON.parse(event.body);
const shortCode = generateShortCode();
await dynamo.send(
new PutCommand({
TableName: tableName,
Item: {
shortCode: shortCode,
originalUrl: requestJSON.url,
createdAt: new Date().toISOString(),
},
})
);
body = {
shortCode: shortCode,
shortUrl: `https://${event.requestContext.domainName}/urls/${shortCode}`,
originalUrl: requestJSON.url,
};
break;
case "GET /urls/{shortCode}":
// Retrieve a specific URL by its short code
const getResult = await dynamo.send(
new GetCommand({
TableName: tableName,
Key: {
shortCode: event.pathParameters.shortCode,
},
})
);
if (!getResult.Item) {
statusCode = 404;
body = { error: "Short URL not found" };
} else {
body = getResult.Item;
}
break;
case "GET /urls":
// List all stored URLs
const scanResult = await dynamo.send(
new ScanCommand({ TableName: tableName })
);
body = scanResult.Items;
break;
case "DELETE /urls/{shortCode}":
// Delete a URL by its short code
await dynamo.send(
new DeleteCommand({
TableName: tableName,
Key: {
shortCode: event.pathParameters.shortCode,
},
})
);
body = { message: `Deleted short URL ${event.pathParameters.shortCode}` };
break;
default:
throw new Error(`Unsupported route: "${event.routeKey}"`);
}
} catch (err) {
statusCode = 400;
body = { error: err.message };
} finally {
body = JSON.stringify(body);
}
return {
statusCode,
body,
headers,
};
};
What does this code do?
This single function handles all four API operations using a switch statement on event.routeKey. The route key tells the function which HTTP method and path were called.
- POST /urls generates a random 6-character code, saves the mapping to DynamoDB, and returns the short URL.
- GET /urls/{shortCode} looks up a specific short code and returns the original URL.
- GET /urls scans the table and returns all stored URLs.
- DELETE /urls/{shortCode} removes a URL from the table.
- Click Deploy to save your code to the Lambda function.
You should see a banner confirming the function was updated successfully.
Seeing a deployment error?
Make sure you replaced ALL the default code. If any of the original template code remains, the function will fail to deploy. Select all (Cmd+A) and paste again.
help me fix my Lambda deployment error
✔️ Awesome, I've got everything!
Great. Make sure you clicked Deploy and saw the success confirmation before moving on.
ⓧ I'd like to double check the full code
Here is the complete index.mjs file. Compare it against what you have in the Lambda editor:
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
import {
DynamoDBDocumentClient,
ScanCommand,
PutCommand,
GetCommand,
DeleteCommand,
} from "@aws-sdk/lib-dynamodb";
const client = new DynamoDBClient({});
const dynamo = DynamoDBDocumentClient.from(client);
const tableName = "url-shortener-links";
function generateShortCode() {
const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
let result = "";
for (let i = 0; i < 6; i++) {
result += chars.charAt(Math.floor(Math.random() * chars.length));
}
return result;
}
export const handler = async (event) => {
let body;
let statusCode = 200;
const headers = {
"Content-Type": "application/json",
};
try {
switch (event.routeKey) {
case "POST /urls":
const requestJSON = JSON.parse(event.body);
const shortCode = generateShortCode();
await dynamo.send(
new PutCommand({
TableName: tableName,
Item: {
shortCode: shortCode,
originalUrl: requestJSON.url,
createdAt: new Date().toISOString(),
},
})
);
body = {
shortCode: shortCode,
shortUrl: `https://${event.requestContext.domainName}/urls/${shortCode}`,
originalUrl: requestJSON.url,
};
break;
case "GET /urls/{shortCode}":
const getResult = await dynamo.send(
new GetCommand({
TableName: tableName,
Key: {
shortCode: event.pathParameters.shortCode,
},
})
);
if (!getResult.Item) {
statusCode = 404;
body = { error: "Short URL not found" };
} else {
body = getResult.Item;
}
break;
case "GET /urls":
const scanResult = await dynamo.send(
new ScanCommand({ TableName: tableName })
);
body = scanResult.Items;
break;
case "DELETE /urls/{shortCode}":
await dynamo.send(
new DeleteCommand({
TableName: tableName,
Key: {
shortCode: event.pathParameters.shortCode,
},
})
);
body = { message: `Deleted short URL ${event.pathParameters.shortCode}` };
break;
default:
throw new Error(`Unsupported route: "${event.routeKey}"`);
}
} catch (err) {
statusCode = 400;
body = { error: err.message };
} finally {
body = JSON.stringify(body);
}
return {
statusCode,
body,
headers,
};
};
Test the function
Before connecting an API, you can test the Lambda function directly. You'll create a test event that simulates what API Gateway would send when someone makes a POST request.
- Click the Test tab in your function's page.
- Under Test event, choose Create new event.
- For Event name, enter createUrl.
- Replace the default JSON with the following test event:
{
"routeKey": "POST /urls",
"body": "{\"url\": \"https://www.amazon.com/jobs\"}",
"requestContext": {
"domainName": "test.execute-api.us-east-1.amazonaws.com"
}
}
What does this test event simulate?
This JSON mimics what API Gateway sends to your Lambda function when someone makes a POST request to create a short URL. The routeKey tells your handler which switch case to run. The body contains the long URL to shorten.
- Click Save changes to save the test event.
- Click Test to invoke the function.
Under Execution result, expand Details. You should see a response with statusCode: 200 and a JSON body containing shortCode, shortUrl, and originalUrl.
Seeing an error in the execution result?
If you see an AccessDeniedException, your role may not have the correct policy attached. Go to the Configuration tab, then Permissions, and verify the role url-shortener-role has the Simple microservice permissions policy.
If you see a syntax error, go back to the Code tab and compare your code against the double-check tab above. Make sure you clicked Deploy after pasting.
help me debug my Lambda function test failure
Your Lambda function is deployed and responding correctly. Next, you'll connect it to API Gateway so it can receive real HTTP requests from anywhere on the internet.
Set Up API Gateway
Your Lambda function can handle all four URL shortener operations, but there is no way to reach it from the outside world yet.
In this step, you will create an HTTP API in Amazon API Gateway that exposes four public routes. Each route maps to a different HTTP method and path, and all four connect to the same Lambda function.
In this step, get ready to:
- Create an HTTP API in API Gateway.
- Add four routes and attach a Lambda integration to each one.
- Copy your live invoke URL.
Create the HTTP API
API Gateway is the front door for your Lambda function. It receives HTTP requests from any client and routes them to the correct backend.
- Search for API Gateway in the top search bar of the AWS Console and open the service.
- Click Create API.
- Under HTTP API, click Build.
- For API name, enter url-shortener-api.
- For IP address type, select IPv4.
- Click Next.
- On the Configure routes page, click Next to skip route creation for now.
- Review the default stage that API Gateway creates, then click Next.
- Click Create.
Why HTTP API instead of REST API?
API Gateway offers two flavours: HTTP API and REST API. HTTP API is Amazon's newer, simpler option designed for most use cases. It has fewer configuration steps, lower latency, and costs less per request.
REST API adds advanced features like request validation and API keys, but you do not need any of those for this project.
You should see your new url-shortener-api listed on the API Gateway dashboard.
Don't see the HTTP API option?
Make sure you are clicking Build under the HTTP API card, not under REST API. REST API has a different creation flow. Help me find the HTTP API Build button in the API Gateway console.
Create routes and attach the Lambda integration
Routes tell API Gateway which Lambda function to call based on the HTTP method and path. You need four routes to match the four event.routeKey cases in your handler.
- Select your url-shortener-api, then choose Routes from the left menu.
- Click Create.
- For Method, choose POST.
- For the path, enter /urls.
- Click Create.
- Repeat the same steps to create three more routes:
What is {shortCode} in the path?
The curly braces mark a path parameter. When a client requests /urls/abc123, API Gateway captures abc123 and passes it to your Lambda function as event.pathParameters.shortCode.
Now create the Lambda integration and attach it to all four routes.
- Choose Integrations from the left menu.
- Click Manage integrations, then click Create.
- For Integration type, choose Lambda function.
- For Lambda function, enter url-shortener-function.
- Click Create.
Next, attach this integration to each of your four routes.
- Go back to Integrations and select the POST /urls route.
- Under Choose an existing integration, select url-shortener-function.
- Click Attach integration.
- Repeat for the remaining three routes: GET /urls, GET /urls/{shortCode}, and DELETE /urls/{shortCode}.
All four routes should now show an AWS Lambda integration attached.
Route not showing an integration?
Make sure you clicked Attach integration after selecting the function for each route. If a route still shows no integration, select it again, choose url-shortener-function from the dropdown, and click Attach integration. Help me attach my Lambda integration to all four API Gateway routes.
Note your invoke URL
Every HTTP API gets a public invoke URL that you can call from anywhere. You will use this URL to test your API in the next step.
- From the left menu, click API: url-shortener-api to return to the details page.
- Find the Invoke URL field and copy the URL.
- Paste it somewhere safe (a text file or sticky note). It looks like https://xxxxxxx.execute-api.us-east-1.amazonaws.com.
What is the invoke URL?
This is the base address for your API. Any HTTP request sent to this URL followed by one of your routes (for example /urls) will be forwarded to your Lambda function.
Your API is live and publicly accessible. Next up, you will test all four CRUD operations from your terminal using curl.
Test Your Live API
Your serverless backend is fully assembled. Lambda handles the logic, DynamoDB stores the data, and API Gateway exposes it all to the internet.
Now it's time to prove it works. You'll send real HTTP requests to your live API using curl in Terminal and watch URLs get created, retrieved, and deleted in real time.
In this step, get ready to:
- Create a short URL by sending a POST request to your API.
- Retrieve and list stored URLs with GET requests.
- Delete a URL and confirm it disappears from DynamoDB.
Create a short URL
Your API is live on the internet. Anyone with the invoke URL can send requests to it. You'll use curl, a command-line tool for making HTTP requests, to test each route.
- Press Cmd+Space to open your search bar.
- Type Terminal and press Enter to open it.
- Send a POST request to create your first short URL by running this command:
curl -X POST -H "Content-Type: application/json" \
-d '{"url": "https://www.amazon.jobs/en/teams/internships"}' \
[[INVOKE_URL="https://your-api-id.execute-api.us-east-1.amazonaws.com"]]/urls
What does this command do?
This curl command sends an HTTP POST request to your API's /urls route.
- -X POST tells curl to use the POST HTTP method.
- -H "Content-Type: application/json" sets the request header so your API knows it's receiving JSON data.
- -d provides the JSON body containing the long URL you want to shorten.
You should see a JSON response containing three fields: shortCode, shortUrl, and originalUrl.
- Copy the shortCode value from your response. You'll use it in the next commands.
Seeing an error or empty response?
- Double-check that you replaced the invoke URL with the one you copied from API Gateway in the previous step.
- Make sure the URL ends with /urls (no trailing slash after /urls).
- Confirm your JSON body uses double quotes around keys and values, not single quotes.
Why is my curl POST request returning an error?
Retrieve and list URLs
Now that you have a URL stored in DynamoDB, you can read it back using GET requests.
- List all stored URLs by running this command:
curl [[INVOKE_URL="https://your-api-id.execute-api.us-east-1.amazonaws.com"]]/urls
You should see a JSON array containing the URL you just created, with its shortCode, originalUrl, and createdAt fields.
- Retrieve a specific URL by running this command (replace the short code with your actual value from the POST response):
curl [[INVOKE_URL="https://your-api-id.execute-api.us-east-1.amazonaws.com"]]/urls/[[SHORT_CODE="your-short-code"]]
You should see a single JSON object with the full details of that specific short URL.
What is a REST API?
REST is a pattern for building APIs where each URL represents a resource, and HTTP methods (GET, POST, DELETE) define what action to take. Your API follows this pattern perfectly.
GET reads data, POST creates data, and DELETE removes data. The URL path (/urls or /urls/{shortCode}) tells the API which resource you're targeting.
Getting a 404 or empty array?
- If the list returns an empty array, your POST request may not have succeeded. Go back and run the POST command again.
- If you get a 404 on the specific URL lookup, make sure you copied the exact shortCode from your POST response (it's case-sensitive).
Why is my GET request returning a 404 or empty results?
Delete a URL
The final CRUD operation is Delete. This removes the URL mapping from DynamoDB entirely.
- Delete your short URL by running this command:
curl -X DELETE [[INVOKE_URL="https://your-api-id.execute-api.us-east-1.amazonaws.com"]]/urls/[[SHORT_CODE="your-short-code"]]
You should see a JSON response confirming the deletion.
- Confirm the deletion by listing all URLs again:
curl [[INVOKE_URL="https://your-api-id.execute-api.us-east-1.amazonaws.com"]]/urls
The response should now be an empty array, confirming the URL was removed.
- Switch back to the AWS Console in your browser.
- Navigate to the DynamoDB console and select your url-shortener-links table.
- Click Explore table items to verify the table is empty.
Why check DynamoDB directly?
Verifying in the DynamoDB console confirms that your Lambda function is actually writing to and deleting from the database. The API response alone could theoretically be faked, but seeing items appear and disappear in DynamoDB proves the entire pipeline works end to end.
Still seeing items in DynamoDB?
- Click the refresh icon in the DynamoDB console. The table view does not update automatically.
- Make sure the shortCode in your DELETE command matches the exact code stored in the table (check capitalization).
Why is my DELETE request not removing the item from DynamoDB?
Secret mission
Add Click Tracking
What happens when someone actually clicks a shortened URL? Right now, your API stores and retrieves URLs but doesn't track usage. Add a redirect route that counts every click using DynamoDB atomic counters and returns an HTTP 301 redirect to the original URL.
Clean Up Your Resources
Clean Up Your Resources
Decide whether to keep your resources running, pause them to come back later, or delete them entirely. All resources in this project fall within the AWS Free Tier, so there are no ongoing costs as long as you stay within free tier limits.
Resources you used:
- DynamoDB table url-shortener-links (Always Free: 25 RCU, 25 WCU, 25 GB storage).
- Lambda function url-shortener-function (Always Free: 1M requests/month).
- HTTP API url-shortener-api on API Gateway (1M calls/month free for 12 months).
- IAM role url-shortener-role (no cost).
- CloudWatch log group /aws/lambda/url-shortener-function (created automatically by Lambda).
Keep everything running
No action needed. Choose this if you plan to demo the API in interviews or continue building on it.
- These resources cost $0 within Free Tier limits. Lambda and DynamoDB are Always Free. API Gateway is free for 1M HTTP API calls/month for the first 12 months.
- Your API stays live and callable from anywhere. You can use it to demo your serverless skills.
- A CloudWatch log group will accumulate logs each time you call the API. These are negligible in size for a learning project.
Pause - I'll come back to this later
Serverless resources only run when called, so there is nothing actively running to pause. Your resources are effectively paused by default when no requests are hitting the API.
- Stop sending requests to the API. No requests means no Lambda invocations and no DynamoDB reads or writes.
- Your data in DynamoDB persists at no cost within free tier storage limits (25 GB).
- When you are ready to come back, everything will work exactly as you left it.
Delete - I don't want to use this again
Remove all project resources completely. Follow each step below in order.
- Delete the HTTP API: search "API Gateway" in the console search bar, open the APIs page, select url-shortener-api, choose Actions, then choose Delete. Choose Delete again to confirm.
- Delete the Lambda function: search "Lambda" in the console search bar, open the Functions page, select url-shortener-function, choose Actions, then Delete. Type confirm in the text input field and choose Delete.
- Delete the DynamoDB table: search "DynamoDB" in the console search bar, open the Tables page, select url-shortener-links, choose Delete. Enter delete in the text box and choose Delete table.
- Delete the IAM role: search "IAM" in the console search bar, choose Roles from the left navigation, select url-shortener-role, choose Delete. Enter the role name in the text input field and choose Delete.
- Delete the CloudWatch log group: search "CloudWatch" in the console search bar, choose Log groups under Logs in the left navigation, select /aws/lambda/url-shortener-function, choose Actions, then Delete log group(s). Choose Delete to confirm.
That's a Wrap!
That's a Wrap!
Nice work! You just built a fully functional serverless REST API on AWS that you can demo live from any machine with curl.
You've learned how to:
- Built a DynamoDB table with a single-table NoSQL design for URL mappings.
- Created a Lambda function in Node.js 22.x that handles CRUD operations using AWS SDK v3.
- Configured an HTTP API in API Gateway with four routes and a Lambda integration, then tested it live using curl.
- Secret Mission: Added click tracking with atomic DynamoDB counters and HTTP 301 redirects.
Ready to quiz yourself?