Content:
{
"id": "quiz-001",
"title": "AWS Basics Quiz",
"questions": [
{
"id": "q1",
"text": "Which AWS services are serverless?",
"type": "multiple",
"options": ["EC2", "S3", "Lambda", "Fargate"],
"answer": [1, 2, 3]
},
{
"id": "q2",
"text": "What is the max size of an S3 object?",
"type": "single",
"options": ["5 GB", "50 GB", "5 TB", "50 TB"],
"answer": [2]
}
]
}
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::myprojectbucket1290/*"
}
]
}
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::myprojectbucket1290/*"
}
]
}
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": "s3:DeleteObject",
"Resource": "arn:aws:s3:::myprojectbucket1290/*"
}
]
}
Name the policy and create it.
Now go to Roles → Create Role. Each policy will have their own role
Create 4 Lambda functions using Node.js 20.x or 22.x. Use the following names and HTTP methods:
Example: myGetFunction
import { S3Client, GetObjectCommand } from "@aws-sdk/client-s3";
import { Readable } from "stream";
const s3 = new S3Client({});
const BUCKET = "myprojectbucket1290"; //Change bucket name here
const streamToString = (stream) =>
new Promise((resolve, reject) => {
const chunks = [];
stream.on("data", (chunk) => chunks.push(chunk));
stream.on("error", reject);
stream.on("end", () => resolve(Buffer.concat(chunks).toString("utf-8")));
});
export const handler = async (event) => {
const key = event.queryStringParameters?.key || "quiz.json";
console.log("🔍 GET request for key:", key);
try {
const res = await s3.send(new GetObjectCommand({ Bucket: BUCKET, Key: key }));
const data = await streamToString(res.Body);
console.log(" Successfully retrieved:", key);
return {
statusCode: 200,
body: data,
headers: { "Content-Type": "application/json" }
};
} catch (err) {
console.error(" Error reading object:", err);
return { statusCode: 500, body: JSON.stringify({ error: err.message }) };
}
};
Repeat similarly for POST (create), PUT (update), and DELETE. Use the code below:
Example: myPostFunction
import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";
const s3 = new S3Client({});
const BUCKET = "myprojectbucket1290";
export const handler = async (event) => {
const body = JSON.parse(event.body || "{}");
const key = body.key || "quiz.json";
const data = body.data;
console.log(" POST request:", { key, data });
if (!data) {
console.warn(" Missing 'data' in request");
return { statusCode: 400, body: "Missing 'data' in request body" };
}
try {
await s3.send(new PutObjectCommand({
Bucket: BUCKET,
Key: key,
Body: JSON.stringify(data),
ContentType: "application/json"
}));
console.log(" Created quiz:", key);
return { statusCode: 200, body: `Created quiz: ${key}` };
} catch (err) {
console.error(" Error creating object:", err);
return { statusCode: 500, body: JSON.stringify({ error: err.message }) };
}
};
Example: myPutFunction
import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";
const s3 = new S3Client({});
const BUCKET = "myprojectbucket1290";
export const handler = async (event) => {
const key = event.queryStringParameters?.key || "quiz.json";
const body = JSON.parse(event.body || "{}");
const data = body.data;
console.log(" PUT request to update:", { key, data });
if (!data) {
console.warn(" Missing 'data' in request");
return { statusCode: 400, body: "Missing 'data' in request body" };
}
try {
await s3.send(new PutObjectCommand({
Bucket: BUCKET,
Key: key,
Body: JSON.stringify(data),
ContentType: "application/json"
}));
console.log(" Updated quiz:", key);
return { statusCode: 200, body: `Updated quiz: ${key}` };
} catch (err) {
console.error("❌ Error updating object:", err);
return { statusCode: 500, body: JSON.stringify({ error: err.message }) };
}
};
Example: myDeleteFunction
import { S3Client, DeleteObjectCommand } from "@aws-sdk/client-s3";
const s3 = new S3Client({});
const BUCKET = "myprojectbucket1290";
export const handler = async (event) => {
const key = event.queryStringParameters?.key || "quiz.json";
console.log(" DELETE request for:", key);
try {
await s3.send(new DeleteObjectCommand({ Bucket: BUCKET, Key: key }));
console.log(" Deleted quiz:", key);
return { statusCode: 200, body: `Deleted quiz: ${key}` };
} catch (err) {
console.error(" Error deleting object:", err);
return { statusCode: 500, body: JSON.stringify({ error: err.message }) };
}
};
Test all functions to confirm they’re working properly.
myGetFunction
myPostFunction
{
"key": "quiz-aws.json",
"data": { "id": "quiz-aws", "title": "AWS Quiz", "questions": [] }
}
myPutFunction
myDeleteFunction
{
"queryStringParameters": {
"key": "quiz-aws.json"
}
}
Final result:
###5. Test with Postman
From API Gateway dashboard, choose your api gateway
Next, click on your api gateway name to view the detail
Copy the invoke URL and open postman for testing:
You now have a complete CRUD-capable quiz API backed by:
This setup forms the foundation of your serverless, event-driven learning platform.