Personal Bookmark Saver
The goal of this project is to create a simple web app to save your favorites, add tags and notes, search or export bookmarks.
What will be used
- Cognito: Handle user authentication.
- API Gateway: Expose API endpoints for frontend (add, list, delete).
- Lambda: Handle backend logic (read/write bookmarks).
- DynamoDB: Store bookmarks (URL, title, tags, timestamp, notes, etc.).
- S3: Host the frontend (HTML/JS).
Create DynamoDB Table
Go to DynamoDB, create a table:
- Table name: Bookmarks
- Partition key: userId (String)
- Sort key: timestamp (Number)
Add attributes:
- url (String)
- title (String)
- tags (String)
- notes (String)
Set Up Cognito
Go to Amazon Cognito:
- Create a User Pool and a User Pool App Client.
- Enable email/password sign-up.
- Enable hosted UI if needed.
- Use Cognito Identity Pool for temporary AWS credentials in frontend.
Create Lambda Functions
Here are the different functions:
- addBookmark
import boto3
import json
import time
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('Bookmarks')
def lambda_handler(event, context):
body = json.loads(event['body'])
user_id = event['requestContext']['authorizer']['claims']['sub'] # Cognito user ID
timestamp = int(time.time())
item = {
'userId': user_id,
'timestamp': timestamp,
'url': body['url'],
'title': body['title'],
'tags': body.get('tags', ''),
'notes': body.get('notes', '')
}
table.put_item(Item=item)
return {
'statusCode': 200,
'body': json.dumps({'message': 'Bookmark added'})
}
import boto3
import json
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('Bookmarks')
def lambda_handler(event, context):
user_id = event['requestContext']['authorizer']['claims']['sub']
response = table.query(
KeyConditionExpression=boto3.dynamodb.conditions.Key('userId').eq(user_id),
ScanIndexForward=False # latest first
)
return {
'statusCode': 200,
'body': json.dumps(response['Items'])
}
import boto3
import json
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('Bookmarks')
def lambda_handler(event, context):
user_id = event['requestContext']['authorizer']['claims']['sub']
body = json.loads(event['body'])
table.delete_item(
Key={
'userId': user_id,
'timestamp': body['timestamp']
}
)
return {
'statusCode': 200,
'body': json.dumps({'message': 'Bookmark deleted'})
}
import boto3
import json
import csv
import io
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('Bookmarks')
def lambda_handler(event, context):
user_id = event['requestContext']['authorizer']['claims']['sub']
response = table.query(
KeyConditionExpression=boto3.dynamodb.conditions.Key('userId').eq(user_id)
)
bookmarks = response['Items']
output = io.StringIO()
writer = csv.DictWriter(output, fieldnames=['url', 'title', 'tags', 'notes', 'timestamp'])
writer.writeheader()
for item in bookmarks:
writer.writerow({
'url': item.get('url', ''),
'title': item.get('title', ''),
'tags': item.get('tags', ''),
'notes': item.get('notes', ''),
'timestamp': item.get('timestamp', '')
})
return {
'statusCode': 200,
'headers': {
'Content-Type': 'text/csv',
'Content-Disposition': 'attachment; filename="bookmarks.csv"'
},
'body': output.getvalue()
}
Create API Gateway
Create a HTTP API.
Add routes:
- POST /add-bookmark → addBookmark Lambda
- GET /list-bookmarks → listBookmarks Lambda
- POST /delete-bookmark -> deleteBookmark Lambda
- GET /export-bookmarks -> exportBookmarks
Enable CORS for frontend use.
Fnable authorization for Cognito.
Build the Frontend
Simple HTML + JS interface:
<form onsubmit="saveBookmark(); return false;">
<input id="url" placeholder="URL"><br>
<input id="title" placeholder="Title"><br>
<input id="tags" placeholder="Tags"><br>
<textarea id="notes" placeholder="Notes"></textarea><br>
<button type="submit">Save</button>
</form>
<pre id="response"></pre>
<script>
async function saveBookmark() {
const data = {
url: document.getElementById('url').value,
title: document.getElementById('title').value,
tags: document.getElementById('tags').value,
notes: document.getElementById('notes').value
};
const res = await fetch("https://your-api-id.amazonaws.com/add-bookmark", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(data)
});
const result = await res.json();
document.getElementById("response").textContent = JSON.stringify(result, null, 2);
}
</script>
Create your S3 bucket:
- Go to the AWS Console → S3 → Create bucket
- Give it a name like my-bookmark-app
- Region: same as your Lambda/API if possible
- Uncheck "Block all public access"
- Acknowledge the warning checkbox
Enable Static Website Hosting
- After creating the bucket, go to Properties tab
- Scroll to Static website hosting
- Click Edit → Enable
- Set:
- Index document: index.html
- (optional) Error document: error.html
- Click Save changes
Upload Your HTML File defined earlier
Make the HTML Public
- Go to the uploaded index.html
- Click Permissions tab → Edit → Set object to public
- Or use a Bucket Policy (recommended for multiple files):
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicRead",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::my-bookmark-app/*"
}
]
}
Replace my-bookmark-app with your bucket name.
Your static site is now live at (replace yourRegion): http://my-bookmark-app.s3-website-yourRegion.amazonaws.com