Build a Study Buddy API with Lambda
Build a serverless REST API that uses Claude AI to generate study content.
Introduction
30 Second Summary
Imagine having a personal tutor available 24/7 who can summarize any topic, quiz you on it, or build a custom study plan. That is exactly the kind of tool developers build with AI APIs.
In this project, you will build a serverless REST API called "Study Buddy" that takes a topic and a mode, then returns AI-generated learning content. You'll wire up AWS Lambda, API Gateway, and Claude's API into a live HTTPS endpoint you can call from anywhere.
What You'll Build
A serverless Study Buddy REST API powered by Lambda and API Gateway that calls Claude to generate summaries, quizzes, and study plans.
By the end of this project, you'll have:
- A live REST API endpoint that accepts a study topic and returns AI-generated content.
- A Lambda layer packaging the Anthropic Python SDK as a reusable dependency.
- A multi-mode API design that routes requests to different AI prompt templates based on a mode parameter.
- Secret Mission: Add request logging with DynamoDB for usage analytics.
Are there any prerequisites?
You'll need an AWS account with free tier active and an Anthropic API key (free credits available at console.anthropic.com). Some familiarity with the AWS Console and basic Python will help, but every step is guided.
Get Your Anthropic API Key
Your Study Buddy API uses Claude as its AI brain. Claude is Anthropic's AI model, and you access it through their API using an API key.
In this step, you'll generate your Anthropic API key, confirm it works with a quick test call, and sign into the AWS Console so you're ready for the next steps.
In this step, get ready to:
- Sign up for Anthropic and generate an API key.
- Test the key with a Python script.
- Sign into the AWS Management Console.
Sign up at console.anthropic.com and generate an API key
Anthropic's developer console is where you manage API keys and monitor usage. You'll create an account and generate a key that your Lambda function will use later.
- Open your browser and go to console.anthropic.com.
- Click Sign Up and create an account using your email, Google, or Apple.
- Verify your email by clicking the confirmation link in your inbox.
- Complete phone verification by entering your mobile phone number and the SMS code you receive.
Why phone verification?
Anthropic requires SMS verification before granting API access. You need a mobile number that can receive text messages.
- Once verified, click Settings in the left sidebar.
- Select API Keys.
- Click Create Key.
- Give your key a name like study-buddy and click Create Key.
- Copy the key immediately and save it somewhere secure (a password manager or a local text file). You will not be able to see it again after closing this dialog.
What about free credits?
New Anthropic accounts receive a small amount of free credits (around $5). This is more than enough for the test calls in this project, which cost fractions of a cent each.
No credit card is required to claim the initial credits. You only need a payment method if you exceed them.
Test the key locally with a Python script
Before wiring the key into Lambda, you'll verify it works by making a quick API call from your local machine. This catches any account issues early.
- Press Cmd+Space (macOS) or the Windows key (Windows) to open your search bar.
- Type Terminal (macOS) or PowerShell (Windows) and press Enter to open it.
- Install the anthropic Python package by running this command:
pip install anthropic
Command not found?
If pip is not recognized, try pip3 instead. You need Python 3.9 or later installed on your machine to proceed.
Help me install Python on my machine.
- Create a file called test_key.py and paste in the following code:
import anthropic
# Create a client with your API key
client = anthropic.Anthropic(api_key="your-api-key-here")
# Send a simple test message to Claude
response = client.messages.create(
model="claude-haiku-4-5",
max_tokens=100,
messages=[{"role": "user", "content": "Say hello in one sentence."}],
)
# Print the response
print(response.content[0].text)
What does this code do?
This script creates an Anthropic client using your API key, sends a short prompt to the claude-haiku-4-5 model, and prints the response.
Replace your-api-key-here with the actual key you copied from the Anthropic Console. Keep the quotes around it.
- Replace your-api-key-here in the script with your actual API key.
- Run the test script by executing this command:
python test_key.py
You should see a short greeting from Claude printed in your terminal (something like "Hello! How can I help you today?").
Seeing an authentication error?
Double-check that you pasted the full API key with no extra spaces. Make sure it is wrapped in quotes in your script.
If you see a permissions error, your account may still be setting up. Wait a minute and try again.
Help me fix my Anthropic authentication error.
- Once the test succeeds, delete test_key.py from your machine. You won't need it again and it contains your API key in plain text.
Why Claude Haiku 4.5?
Your Study Buddy API uses claude-haiku-4-5 because it responds in 2-5 seconds and costs just $1 per million input tokens and $5 per million output tokens.
A typical study request costs about $0.003. That makes it ideal for a serverless API where speed and cost both matter.
Sign into the AWS Management Console
The rest of this project takes place in AWS. Sign in now so you're ready to build.
- Open aws.amazon.com/console in your browser.
- Sign in with your AWS account credentials.
- Confirm you see the AWS Management Console dashboard with the search bar at the top.
Your API key is confirmed working and your AWS Console is ready. Next up, you'll package the Anthropic Python SDK as a Lambda layer so your serverless function can use it.
Build the Lambda Layer in CloudShell
Your Lambda function needs the Anthropic Python SDK to call Claude's API. Lambda doesn't include third-party packages by default, so you need to provide them separately as a layer.
A Lambda layer is a zip archive containing libraries that Lambda loads alongside your function code. You'll build yours in AWS CloudShell, a browser-based terminal that runs Amazon Linux and produces binaries fully compatible with Lambda's runtime.
In this step, get ready to:
- Open AWS CloudShell from the AWS Management Console.
- Install the Anthropic SDK into a layer-compatible directory structure.
- Zip and publish the layer to AWS Lambda.
Open AWS CloudShell
CloudShell gives you a pre-authenticated Linux terminal directly in your browser. The AWS CLI is already installed and configured with your console credentials.
- In the AWS Management Console, click the CloudShell icon on the console navigation bar (it looks like a terminal prompt).
- Wait for the shell to initialize. When you see a command prompt ending in $, the shell is ready.
Why build the layer in CloudShell?
Lambda runs on Amazon Linux. Some Python packages (like the Anthropic SDK) contain compiled C extensions that must match the operating system. If you build the layer on Windows or macOS, those binaries won't work inside Lambda.
CloudShell runs Amazon Linux natively, so everything you install with pip is automatically compatible with Lambda's execution environment.
Don't see the CloudShell icon?
You can also type CloudShell in the console search bar at the top of the page and select it from the results.
If CloudShell isn't available in your selected region, it will automatically connect to the nearest supported region.
Help me open CloudShell in the AWS Console.
Install the Anthropic SDK into the layer directory
Lambda layers require a specific directory structure. For Python, the packages must live inside a top-level python/ directory.
- Create the required directory and install the Anthropic package into it by running these commands:
mkdir python
pip install anthropic -t python/
What do these commands do?
mkdir python creates the directory structure Lambda expects for a Python layer.
pip install anthropic -t python/ installs the Anthropic SDK and all its dependencies into that directory instead of the default system location. The -t flag means "target directory".
- Confirm the packages installed correctly by running:
ls python/
You should see folders like anthropic, httpx, pydantic, and several other dependency directories.
Seeing permission errors or empty directory?
Make sure you ran mkdir python first. If you accidentally typed pip install anthropic -t python without the leading mkdir, pip will create the directory for you, but double-check that it exists with ls.
If pip reports a network error, wait a moment and try again. CloudShell occasionally takes a few seconds to establish internet connectivity after first launching.
Help me install the anthropic package in CloudShell.
Zip and publish the layer
Now you'll package the python/ directory into a zip file and publish it as a Lambda layer using the AWS CLI.
- Create the zip archive by running this command:
zip -r anthropic-layer.zip python/
- Confirm the zip file was created by running:
ls -lh anthropic-layer.zip
You should see anthropic-layer.zip listed with a size of roughly 20-40 MB.
- Publish the zip as a Lambda layer by running this command:
aws lambda publish-layer-version --layer-name anthropic-sdk --zip-file fileb://anthropic-layer.zip --compatible-runtimes python3.13
What does this command do?
aws lambda publish-layer-version uploads your zip file to AWS and registers it as a reusable layer.
--layer-name anthropic-sdk gives the layer a name you'll reference when attaching it to your function.
--compatible-runtimes python3.13 tells AWS this layer works with the python3.13 runtime, which is the runtime you'll choose for your Lambda function.
- Look for the LayerVersionArn field in the JSON output. Copy this value and save it somewhere. You'll need it in the next step when configuring your Lambda function.
The ARN looks something like arn:aws:lambda:us-east-1:123456789012:layer:anthropic-sdk:1. Your region and account number will differ.
Seeing an access denied error?
Your IAM user or role needs permission to call lambda:PublishLayerVersion. If you're using an admin account or a user with AdministratorAccess, this won't be an issue.
If the upload times out, your zip file may be too large. Confirm it is under 50 MB with ls -lh anthropic-layer.zip.
Help me publish my Lambda layer from CloudShell.
Your Lambda layer is live. Next up, you'll create the Lambda function itself and attach this layer so it can import the Anthropic SDK.
Create the Lambda Function
Your Lambda layer is ready with the Anthropic SDK packaged inside it. Now you need a Lambda function that uses that layer to call Claude and return study content.
In this step, you will create the Lambda function itself, wire up the layer and environment variable, and paste in the handler code that routes requests to different AI prompt templates.
In this step, get ready to:
- Create a Lambda function with the Python 3.13 runtime.
- Attach the layer, set the API key, and configure timeout and memory.
- Deploy the handler code that parses requests and calls Claude.
Create the Lambda function in the AWS Console
Every Lambda function needs a runtime (the language version it runs on) and an execution role (the permissions it has). When you create a function through the console, Lambda auto-generates an execution role with basic logging permissions.
- Open the Functions page of the Lambda console.
- Choose Create function.
- Select Author from scratch.
- For Function name, enter StudyBuddy.
- For Runtime, choose Python 3.13.
- Leave architecture set to x86_64.
- Choose Create function.
Lambda creates your function and opens its detail page. You should see a green banner confirming the function was created successfully.
What just happened?
Lambda created your function with a default execution role that has permission to write logs to CloudWatch. It also created a starter lambda_function.py file with a placeholder handler. You will replace that code shortly.
Don't see Python 3.13 in the dropdown?
Make sure you are in a region that supports the python3.13 runtime. Most regions support it. If it is missing, switch to us-east-1 or us-west-2 using the region selector in the top-right corner of the console.
Still stuck? Help me find the Python 3.13 runtime in the Lambda console.
Configure the layer, environment variable, timeout, and memory
The default Lambda configuration gives your function 128 MB of memory and a 3-second timeout. Calling an external AI API needs more time and memory than that.
- On the function detail page, scroll down to the Layers section.
- Choose Add a layer.
- Under Choose a layer, select Custom layers.
- Select your anthropic-sdk layer from the dropdown and choose the latest version.
- Choose Add.
You should see the layer listed under the Layers section with a count of 1.
Why attach a layer?
Lambda layers let you package dependencies separately from your function code. Your anthropic-sdk layer contains the Anthropic Python SDK. Lambda extracts it into /opt/python/ at runtime, making it importable by your handler.
- Choose the Configuration tab, then choose General configuration.
- Choose Edit.
- Set Memory to 256 MB.
- Set Timeout to 30 seconds.
- Choose Save.
Why 30 seconds and 256 MB?
Claude Haiku 4.5 typically responds in 2-5 seconds, but network variability can add latency. A 30-second timeout gives plenty of headroom.
The default 128 MB is tight when loading the Anthropic SDK. Bumping to 256 MB also increases CPU allocation proportionally, which speeds up cold starts.
- Still in the Configuration tab, choose Environment variables.
- Choose Edit.
- Choose Add environment variable.
- For Key, enter ANTHROPIC_API_KEY.
- For Value, paste your Anthropic API key.
- Choose Save.
What is an environment variable in Lambda?
Environment variables store configuration values outside your code. Your function reads ANTHROPIC_API_KEY at runtime using os.environ in Python. This keeps your secret out of source code.
Environment variable not saving?
Make sure the key is at least two characters and contains only letters, numbers, and underscores. Also check that the total size of all environment variables does not exceed 4 KB.
Help me troubleshoot my Lambda environment variable configuration.
Deploy the handler code
Your function is configured. Now you need to replace the placeholder code with the handler that parses incoming requests, selects a prompt template, and calls Claude.
- Choose the Code tab.
- In the code editor, select lambda_function.py in the file explorer on the left.
- Select all the existing code and delete it.
- Paste in the following handler code:
import json
import os
import time
import anthropic
PROMPT_TEMPLATES = {
"summarize": (
"You are a helpful study assistant. Summarize the following topic in 3-5 clear, "
"concise bullet points suitable for a student reviewing the concept:\n\n"
"Topic: {topic}"
),
"quiz": (
"You are a helpful study assistant. Generate 3 multiple-choice quiz questions "
"(with 4 options each and the correct answer marked) for the following topic:\n\n"
"Topic: {topic}\n\n"
"Format each question as:\n"
"Q: [question]\n"
"A) [option]\nB) [option]\nC) [option]\nD) [option]\n"
"Answer: [letter]"
),
"plan": (
"You are a helpful study assistant. Create a 5-day study plan for learning the "
"following topic from scratch. Include daily goals and suggested activities:\n\n"
"Topic: {topic}"
),
}
def lambda_handler(event, context):
# Parse the incoming request body
try:
body = json.loads(event.get("body", "{}"))
except (json.JSONDecodeError, TypeError):
body = event if isinstance(event, dict) else {}
# Extract topic and mode from the request
topic = body.get("topic", "").strip()
mode = body.get("mode", "summarize").strip().lower()
# Validate that a topic was provided
if not topic:
return {
"statusCode": 400,
"headers": {"Content-Type": "application/json"},
"body": json.dumps({
"error": "Missing required field: topic",
"usage": "Send a POST with JSON body: {\"topic\": \"your topic\", \"mode\": \"summarize|quiz|plan\"}"
}),
}
# Validate that the mode is supported
if mode not in PROMPT_TEMPLATES:
return {
"statusCode": 400,
"headers": {"Content-Type": "application/json"},
"body": json.dumps({
"error": f"Invalid mode: {mode}",
"valid_modes": list(PROMPT_TEMPLATES.keys())
}),
}
# Build the prompt from the selected template
prompt = PROMPT_TEMPLATES[mode].format(topic=topic)
# Call the Claude API and measure response time
start = time.time()
try:
client = anthropic.Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])
response = client.messages.create(
model="claude-haiku-4-5",
max_tokens=1024,
messages=[{"role": "user", "content": prompt}],
)
ai_response = response.content[0].text
elapsed = round(time.time() - start, 2)
except Exception as e:
return {
"statusCode": 500,
"headers": {"Content-Type": "application/json"},
"body": json.dumps({"error": f"AI API error: {str(e)}"}),
}
# Return the structured JSON response
return {
"statusCode": 200,
"headers": {"Content-Type": "application/json"},
"body": json.dumps({
"topic": topic,
"mode": mode,
"response": ai_response,
"model": "claude-haiku-4-5",
"response_time_seconds": elapsed,
}, indent=2),
}
What does this code do?
- PROMPT_TEMPLATES is a dictionary with three keys: summarize, quiz, and plan. Each maps to a different AI prompt that shapes the response format.
- lambda_handler is the entry point Lambda calls. It parses the JSON body from the incoming request to extract topic and mode.
- Validation checks return a 400 error if topic is missing or mode is not one of the three supported values.
- The function creates an Anthropic client using the ANTHROPIC_API_KEY environment variable, sends the formatted prompt to claude-haiku-4-5, and measures how long the call takes.
- The response includes the topic, mode, AI-generated text, model name, and response time. This structured format makes the API easy to integrate with any frontend.
- In the DEPLOY section above the code editor, choose Deploy to publish your code.
You should see a green banner confirming your changes have been deployed.
Seeing an error when you deploy?
If you see a syntax error, double-check that you copied the entire code block. A common mistake is missing the closing parenthesis on a multi-line string.
If you see an import error when testing, make sure the anthropic-sdk layer is attached. Check the Layers section at the bottom of the function page.
Help me fix a deployment error in my Lambda function.
✔️ Awesome, I've got everything!
Great. Double check you deployed your code by looking for the green success banner.
ⓧ I'd like to double check the full code
Here is the complete lambda_function.py for comparison:
import json
import os
import time
import anthropic
PROMPT_TEMPLATES = {
"summarize": (
"You are a helpful study assistant. Summarize the following topic in 3-5 clear, "
"concise bullet points suitable for a student reviewing the concept:\n\n"
"Topic: {topic}"
),
"quiz": (
"You are a helpful study assistant. Generate 3 multiple-choice quiz questions "
"(with 4 options each and the correct answer marked) for the following topic:\n\n"
"Topic: {topic}\n\n"
"Format each question as:\n"
"Q: [question]\n"
"A) [option]\nB) [option]\nC) [option]\nD) [option]\n"
"Answer: [letter]"
),
"plan": (
"You are a helpful study assistant. Create a 5-day study plan for learning the "
"following topic from scratch. Include daily goals and suggested activities:\n\n"
"Topic: {topic}"
),
}
def lambda_handler(event, context):
try:
body = json.loads(event.get("body", "{}"))
except (json.JSONDecodeError, TypeError):
body = event if isinstance(event, dict) else {}
topic = body.get("topic", "").strip()
mode = body.get("mode", "summarize").strip().lower()
if not topic:
return {
"statusCode": 400,
"headers": {"Content-Type": "application/json"},
"body": json.dumps({
"error": "Missing required field: topic",
"usage": "Send a POST with JSON body: {\"topic\": \"your topic\", \"mode\": \"summarize|quiz|plan\"}"
}),
}
if mode not in PROMPT_TEMPLATES:
return {
"statusCode": 400,
"headers": {"Content-Type": "application/json"},
"body": json.dumps({
"error": f"Invalid mode: {mode}",
"valid_modes": list(PROMPT_TEMPLATES.keys())
}),
}
prompt = PROMPT_TEMPLATES[mode].format(topic=topic)
start = time.time()
try:
client = anthropic.Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])
response = client.messages.create(
model="claude-haiku-4-5",
max_tokens=1024,
messages=[{"role": "user", "content": prompt}],
)
ai_response = response.content[0].text
elapsed = round(time.time() - start, 2)
except Exception as e:
return {
"statusCode": 500,
"headers": {"Content-Type": "application/json"},
"body": json.dumps({"error": f"AI API error: {str(e)}"}),
}
return {
"statusCode": 200,
"headers": {"Content-Type": "application/json"},
"body": json.dumps({
"topic": topic,
"mode": mode,
"response": ai_response,
"model": "claude-haiku-4-5",
"response_time_seconds": elapsed,
}, indent=2),
}
Your Lambda function is configured and deployed. Next up, you will create an API Gateway endpoint so you can call this function over HTTPS from anywhere.
Set Up API Gateway
Your Lambda function is ready, but it has no public URL. Right now, only the AWS Console or CLI can invoke it directly.
API Gateway solves this by creating an HTTPS endpoint that routes incoming requests to your Lambda function. You'll set up a REST API with a single resource and method, then deploy it to get a live URL anyone can call.
In this step, get ready to:
- Create a REST API with a /study resource.
- Add a POST method with Lambda proxy integration.
- Deploy the API and copy the invoke URL.
Create the REST API and /study resource
A REST API in API Gateway is the container that holds your resources, methods, and integrations. You'll create one and add a /study resource that clients will send requests to.
- In the AWS Console, navigate to the API Gateway service by searching API Gateway in the top search bar and selecting it.
- Click Create API.
- Find the REST API card (not the private one) and click Build.
- For API name, enter StudyBuddyAPI.
- Keep API endpoint type set to Regional.
- For IP address type, select IPv4.
- Click Create API.
You should now see the Resources page with just a root resource (/) listed.
- Click Create resource.
- Keep Proxy resource turned off.
- Keep Resource path as /.
- For Resource name, enter study.
- Keep CORS (Cross Origin Resource Sharing) turned off.
- Click Create resource.
Your Resources tree now shows /study as a child of the root resource.
What is a resource in API Gateway?
A resource is a URL path segment that clients can send requests to. By creating a /study resource, you're defining the path where your API will listen for incoming study requests.
The full URL will eventually look like https://{api-id}.execute-api.{region}.amazonaws.com/dev/study.
Add a POST method with Lambda proxy integration
Lambda proxy integration is the simplest way to connect API Gateway to a Lambda function. API Gateway passes the entire incoming request directly to your function, and your function returns a response with statusCode, headers, and body fields.
- Select the /study resource in the Resources tree.
- Click Create method.
- For Method type, select POST.
- For Integration type, select Lambda function.
- Turn on Lambda proxy integration.
- For Lambda function, search for and select StudyBuddy.
- Click Create method.
What is Lambda proxy integration?
With Lambda proxy integration, API Gateway forwards the entire HTTP request (headers, query strings, body) to your Lambda function as a structured event object. Your function reads the body field from that event to get the JSON payload the client sent.
This is why your handler code uses json.loads(event.get("body", "{}")) to parse the incoming request. The event dictionary is the full request that API Gateway passes through.
Why POST instead of GET?
Your Study Buddy API accepts a JSON body with topic and mode fields. POST is the correct HTTP method for sending structured data in a request body. GET requests typically don't carry a body.
Don't see your Lambda function in the dropdown?
Make sure you're in the same AWS region where you created the StudyBuddy Lambda function. Check the region selector in the top-right corner of the console.
help me find my Lambda function in API Gateway
Deploy the API to a dev stage
Your API exists in draft mode right now. Deploying it to a stage makes it publicly accessible via an HTTPS URL.
- Click Deploy API (in the Resources pane).
- For Stage, select New stage.
- For Stage name, enter dev.
- Click Deploy.
You should now see the Stages page with your dev stage listed.
- In the main navigation pane, click Stages.
- Under Stage details, find the Invoke URL and click the copy icon next to it.
- Paste this URL somewhere safe (a text file or note). You'll need it in the next step for testing.
What does the invoke URL look like?
Your invoke URL follows this format:
https://{api-id}.execute-api.{region}.amazonaws.com/dev
To call your /study resource, you'll append /study to the end of this URL. The full endpoint becomes something like https://abc123.execute-api.us-east-1.amazonaws.com/dev/study.
Seeing a 'Missing Authentication Token' error?
If you try visiting the invoke URL directly in a browser, you'll see this error. That's expected. Your API only accepts POST requests, but a browser sends a GET request. You'll test properly with curl in the next step.
help me understand the Missing Authentication Token error from API Gateway
Your API is live. In the next step, you'll put it to the test by sending real requests with different study modes and verifying the AI-generated responses.
Test Your Study Buddy
Your API is deployed, the Lambda function has its layer and environment variable, and the API Gateway invoke URL is ready.
Now it's time to prove the whole system works end-to-end by sending real HTTP requests and inspecting the AI-generated responses.
In this step, get ready to:
- Test all three study modes (summarize, quiz, plan) with curl requests.
- Verify structured JSON responses from Claude.
- Confirm error handling works for invalid requests.
Send a summarize request
You'll send a POST request to your live API endpoint with a topic and mode, just like a real client application would.
- In the AWS Management Console, click the CloudShell icon on the console navigation bar (to the right of the search box).
- Wait for the shell prompt to appear.
Why CloudShell?
AWS CloudShell is a browser-based terminal that comes with curl pre-installed. It runs in the same AWS region as your console session, so you can test your API without installing anything locally.
- Send your first request to the API by running this command:
curl -X POST [[INVOKE_URL="https://abc123.execute-api.us-east-1.amazonaws.com/dev/study"]] \
-H "Content-Type: application/json" \
-d '{"topic": "photosynthesis", "mode": "summarize"}'
What does this command do?
- curl -X POST sends an HTTP POST request to your API Gateway endpoint.
- -H "Content-Type: application/json" tells the API you're sending JSON in the request body.
- -d '{...}' is the JSON payload containing your topic and mode.
You should see a JSON response containing 3-5 bullet points summarizing photosynthesis, along with metadata like model, response_time_seconds, and the topic you sent.
Seeing an error instead of a response?
- If you see "message": "Missing Authentication Token", double-check your invoke URL ends with /dev/study. A missing resource path causes this error.
- If you see "AI API error", your Anthropic API key may be incorrect. Return to your Lambda function's environment variables and verify the ANTHROPIC_API_KEY value.
- If you see "Internal server error", check that your Lambda timeout is set to 30 seconds and that the anthropic-sdk layer is attached.
Help me debug my Study Buddy API response
Test the quiz and plan modes
Your API supports three modes, each producing a different style of study content. The mode parameter in your request body controls which prompt template the Lambda function uses.
- Test the quiz mode by running this command:
curl -X POST [[INVOKE_URL="https://abc123.execute-api.us-east-1.amazonaws.com/dev/study"]] \
-H "Content-Type: application/json" \
-d '{"topic": "machine learning", "mode": "quiz"}'
You should see a JSON response containing 3 multiple-choice questions about machine learning, each with 4 options and a marked correct answer.
- Test the plan mode by running this command:
curl -X POST [[INVOKE_URL="https://abc123.execute-api.us-east-1.amazonaws.com/dev/study"]] \
-H "Content-Type: application/json" \
-d '{"topic": "Kubernetes", "mode": "plan"}'
You should see a 5-day study plan with daily goals and suggested activities for learning Kubernetes from scratch.
What's happening behind the scenes?
Each request flows through the same path: curl sends a POST to API Gateway, which passes the full request to your Lambda function using Lambda proxy integration. The function parses the body, selects the matching prompt template from PROMPT_TEMPLATES, sends it to Claude, and returns the result as JSON.
Try your own topics
Swap "Kubernetes" for any topic you're actually studying. The API works with any subject. Try "AWS Lambda", "linear algebra", or "French Revolution".
Test error handling
A well-designed API returns helpful error messages when something goes wrong. Your Lambda function validates both the topic and mode fields and returns informative 400-status responses for invalid requests.
- Test the missing-topic error by running this command:
curl -X POST [[INVOKE_URL="https://abc123.execute-api.us-east-1.amazonaws.com/dev/study"]] \
-H "Content-Type: application/json" \
-d '{"mode": "summarize"}'
You should see a 400 response with the error "Missing required field: topic" and a usage hint explaining the expected JSON structure.
- Test the invalid-mode error by running this command:
curl -X POST [[INVOKE_URL="https://abc123.execute-api.us-east-1.amazonaws.com/dev/study"]] \
-H "Content-Type: application/json" \
-d '{"topic": "photosynthesis", "mode": "flashcards"}'
You should see a 400 response with the error "Invalid mode: flashcards" and a valid_modes array listing summarize, quiz, and plan.
Why does error handling matter?
Good error responses help API consumers fix their requests without digging through documentation. The usage field in the missing-topic error tells the caller exactly what format to use. The valid_modes field in the invalid-mode error lists all accepted values.
Secret mission
Add Request Logging with DynamoDB
Your Study Buddy API works great, but you have no idea how people are using it. What topics are they studying? Which mode is most popular? In this secret mission, add a DynamoDB table that logs every request and a /history endpoint that returns recent queries for analytics.
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 charges from Lambda, API Gateway, or DynamoDB at low usage.
Resources you used:
- StudyBuddyAPI REST API in API Gateway (with /study and /history resources).
- StudyBuddy Lambda function.
- StudyBuddyHistory Lambda function.
- anthropic-sdk Lambda layer.
- StudyBuddyLogs DynamoDB table.
- Anthropic API key (stored as a Lambda environment variable).
Keep everything running
No action needed. Choose this if you plan to keep using your Study Buddy API for demos or portfolio showcases.
- Lambda and API Gateway free tiers cover 1 million requests per month. You will only incur costs from the Anthropic API when you make requests.
- DynamoDB free tier covers 25 GB of storage and 25 read/write capacity units (always free).
- Your Anthropic API key remains configured. Each Claude API call costs a fraction of a cent, only when invoked.
Pause - I'll come back to this later
Serverless resources do not run when idle, so there is nothing to "pause" in the traditional sense. To prevent accidental Claude API charges from stray requests, you can remove the API key from your Lambda environment.
- Open the StudyBuddy function in the Lambda console.
- Select the Configuration tab, then Environment variables.
- Remove the ANTHROPIC_API_KEY variable and click Save.
- When you are ready to resume, re-add the environment variable with your key.
Delete - I don't want to use this again
Remove all project resources and start fresh. Follow these steps in order.
Delete the REST API
- Open the API Gateway console.
- Select StudyBuddyAPI.
- Choose API actions, then Delete API.
- Type confirm in the dialog box and choose Delete.
Delete the Lambda functions
- Open the Functions page of the Lambda console.
- Select StudyBuddy.
- Choose Actions, then Delete.
- Type confirm in the text input field and choose Delete.
- Repeat the same steps for the StudyBuddyHistory function.
Delete the Lambda layer
- Open the Layers page of the Lambda console.
- Select the anthropic-sdk layer.
- Select the version and choose Delete.
- Confirm the deletion when prompted.
Delete the DynamoDB table
- Open the DynamoDB console.
- In the left navigation pane, choose Tables.
- Select the StudyBuddyLogs table.
- Choose Delete.
- Enter delete in the text box and choose Delete table.
Revoke your Anthropic API key (optional)
- If you no longer need the key, sign in to console.anthropic.com and delete it from your API keys page.
Nice Work!
Nice Work!
You just built an AI-powered serverless API from scratch. Your Study Buddy takes any topic, routes it through one of three prompt templates, and returns structured learning content through a live HTTPS endpoint.
You've learned how to:
- Built a REST API with API Gateway and Lambda proxy integration that accepts JSON requests and returns structured responses.
- Packaged the Anthropic Python SDK as a reusable Lambda layer using CloudShell to handle cross-platform dependency compilation.
- Designed a multi-mode API that routes requests to different AI prompt templates based on a mode parameter.
- Added request logging with DynamoDB to track usage history through a dedicated /history endpoint.
Ready to quiz yourself?