This content originally appeared on DEV Community and was authored by Shrijith Venkatramana
Hello, I’m Shrijith Venkatramana. I’m building LiveReview, a private AI code review tool that runs on your LLM key (OpenAI, Gemini, etc.) with affordable pricing — built for small teams. Do check it out and give it a try!
If you’re looking to spin up quick APIs without managing servers, AWS Chalice might be your next go-to tool. It’s a Python framework that lets you build and deploy serverless apps on AWS Lambda, and the best part? You can host experimental dynamic APIs for free under AWS’s free tier limits. In this guide, we’ll walk through getting started, from setup to deployment, with plenty of code examples you can copy-paste and run. We’ll keep things practical, focusing on what works for rapid prototyping.
By the end, you’ll have a running API, plus ideas on handling events like S3 uploads or scheduled tasks. All based on Chalice’s straightforward decorator-based approach.
Why Chalice Stands Out for Quick Serverless Builds
Chalice simplifies serverless development by handling the heavy lifting: it generates IAM policies automatically, deploys via a single command, and integrates seamlessly with AWS services like API Gateway, S3, SNS, and SQS.
Key advantages:
- Decorator-driven API: Define routes, schedules, or event handlers with simple Python decorators.
- No server management: Everything runs on Lambda, so scale is automatic.
- Free for experiments: Leverage AWS Lambda’s free tier (1 million requests/month) for low-traffic APIs.
- Python-focused: Supports Python 3.9 to 3.13, matching Lambda’s runtimes.
Compared to alternatives like Serverless Framework or SAM, Chalice feels lighter for Python devs—less YAML config, more code.
Feature | Chalice | Serverless Framework | AWS SAM |
---|---|---|---|
Primary Language | Python | Multi-language | Multi-language |
Deployment Command | chalice deploy |
sls deploy |
sam deploy |
Auto IAM Policies | Yes | Partial | No |
Event Integrations | Built-in decorators for S3, SQS, etc. | Plugins needed | YAML templates |
If you’re new to serverless, Chalice’s minimal setup gets you deploying faster. Check the official GitHub for the latest updates: aws/chalice.
Setting Up Your Local Environment for Chalice
Before coding, get your machine ready. You’ll need Python (3.9+), a virtual environment, and AWS credentials.
First, verify Python:
python3 --version
# Output: Python 3.9.22 (or higher, up to 3.13)
Create and activate a virtual env:
python3 -m venv venv-chalice
source venv-chalice/bin/activate # On macOS/Linux; use venv-chalice\Scripts\activate on Windows
Install Chalice:
pip install chalice
Test it:
chalice --help
# Output: Usage: chalice [OPTIONS] COMMAND [ARGS]...
For AWS access, create ~/.aws/config
if you don’t have one:
mkdir ~/.aws
cat << EOF > ~/.aws/config
[default]
aws_access_key_id=YOUR_ACCESS_KEY
aws_secret_access_key=YOUR_SECRET_KEY
region=us-west-2 # Or your preferred region
EOF
Pro tip: Use AWS IAM for a least-privilege user. If you’re stuck on creds, refer to Boto3’s credential docs.
This setup takes under 5 minutes and ensures smooth deployments.
Creating Your Initial Chalice Project Structure
With tools ready, generate a project skeleton. Run:
chalice new-project my-first-api
cd my-first-api
This creates:
-
app.py
: Your main application file. -
requirements.txt
: For dependencies (empty at start). -
.chalice/
: Config files—don’t edit manually yet.
Peek at the directory:
ls -la
# Output:
# drwxr-xr-x .chalice
# -rw-r--r-- app.py
# -rw-r--r-- requirements.txt
app.py
starts with a basic API:
from chalice import Chalice
app = Chalice(app_name='my-first-api')
@app.route('/')
def index():
return {'hello': 'world'}
This defines a root route returning JSON. No extras needed yet—Chalice handles the rest.
If you add libraries like requests
, update requirements.txt
and Chalice bundles them on deploy.
Exploring app.py: Routes and Basic Functionality
The heart of Chalice is app.py
, where you define your logic using decorators.
Core elements:
-
Chalice(app_name)
: Initializes your app. -
@app.route('/')
: Maps HTTP methods (GET by default) to functions. - Return values: JSON-serializable dicts or strings.
Extend the basic example with a dynamic route:
from chalice import Chalice
app = Chalice(app_name='my-first-api')
@app.route('/')
def index():
return {'hello': 'world'}
@app.route('/greet/{name}')
def greet(name):
return {'message': f'Hello, {name}!'}
Run locally for testing:
chalice local
# Output: Serving on http://127.0.0.1:8000
Curl it:
curl http://127.0.0.1:8000/greet/Dev
# Output: {"message": "Hello, Dev!"}
Chalice supports HTTP methods like POST via methods=['POST']
in the decorator. For full route options, see the Chalice quickstart docs.
This setup lets you prototype APIs quickly without boilerplate.
Deploying Your Chalice App to AWS Lambda
Deployment is Chalice’s killer feature—one command handles packaging, IAM roles, Lambda functions, and API Gateway.
From your project dir:
chalice deploy
# Output:
# Creating deployment package.
# Creating IAM role: my-first-api-dev
# Creating lambda function: my-first-api-dev
# Creating Rest API
# Resources deployed:
# - Lambda ARN: arn:aws:lambda:us-west-2:123456789012:function:my-first-api-dev
# - Rest API URL: https://abcd1234.execute-api.us-west-2.amazonaws.com/api/
Test the live endpoint:
curl https://abcd1234.execute-api.us-west-2.amazonaws.com/api/
# Output: {"hello": "world"}
What happens under the hood:
- Chalice zips your code and deps.
- Creates a Lambda function.
- Sets up API Gateway routes.
- Generates minimal IAM policies.
Redeploy changes with the same command—it updates efficiently.
If issues arise (e.g., permissions), check logs via chalice logs
. For region-specific tips, browse AWS Lambda docs.
Your API is now live, free for light use.
Adding Dynamic Routes and Handling Requests
Build on basics by adding params, queries, and responses.
Enhance with a POST route for data processing:
from chalice import Chalice, Response
app = Chalice(app_name='my-first-api')
@app.route('/echo', methods=['POST'])
def echo():
request = app.current_request
body = request.json_body
if body and 'text' in body:
return Response(body={'echoed': body['text']},
status_code=200,
headers={'Content-Type': 'application/json'})
return Response(body={'error': 'Missing text'},
status_code=400)
Local test:
chalice local
curl -X POST http://127.0.0.1:8000/echo -H "Content-Type: application/json" -d '{"text": "Test message"}'
# Output: {"echoed": "Test message"}
Use app.current_request
for headers, queries, or bodies.
For validation, add libraries like pydantic
to requirements.txt
:
pip install pydantic
echo "pydantic" >> requirements.txt
This keeps APIs robust for experiments.
Triggering Functions with AWS Events
Chalice isn’t just APIs—handle events like S3 uploads or schedules.
For scheduled tasks:
from chalice import Chalice, Rate
app = Chalice(app_name='my-first-api')
@app.schedule(Rate(5, unit=Rate.MINUTES))
def every_five_minutes(event):
print("Running task!")
return {"status": "done"}
Deploy, and it runs every 5 minutes via CloudWatch Events.
For S3 events:
from chalice import Chalice
app = Chalice(app_name='my-first-api')
@app.on_s3_event(bucket='my-experimental-bucket')
def handle_s3_upload(event):
print(f"File uploaded: {event.key}")
# Process the file here
Create the bucket first in AWS console. Deploy to wire it up.
Similar for SQS:
from chalice import Chalice
app = Chalice(app_name='my-first-api')
@app.on_sqs_message(queue='my-queue')
def process_queue(event):
for record in event:
print(f"Message: {record.body}")
These decorators auto-configure triggers. For more event types, explore Chalice’s event docs.
This expands Chalice beyond APIs into full event-driven apps.
Scaling Experiments: Updates, Deletion, and Tips
Once deployed, iterate fast: edit code, chalice deploy
again—it only updates changes.
View logs:
chalice logs
# Output: Tail of Lambda logs...
For cleanup:
chalice delete
# Output:
# Deleting Rest API...
# Deleting Lambda function...
# Deleting IAM role...
Best practices for experiments:
- Version control: Git your project early.
-
Environments: Use
--stage
for dev/prod (e.g.,chalice deploy --stage prod
). - Costs: Monitor AWS console—stay in free tier by limiting invocations.
-
Security: Avoid hardcoding secrets; use environment vars via
.chalice/config.json
.
Command | Purpose | When to Use |
---|---|---|
chalice deploy |
Upload and configure resources | After code changes |
chalice local |
Run API locally | Quick testing |
chalice delete |
Remove all resources | End of experiment |
chalice logs |
Fetch Lambda logs | Debugging issues |
If scaling up, consider Chalice’s blueprints for reusable code.
Next Steps: Building Production-Ready Apps with Chalice
As you experiment more, dive into advanced features like custom domains via API Gateway or integrating with DynamoDB. Start small—prototype an API for a side project, then add events for automation.
Resources to level up:
- Official tutorials: Chalice Tutorials
- Community: Join discussions on GitHub issues or Gitter.
Chalice makes serverless accessible, so tweak these examples and deploy your ideas today. If you hit snags, AWS free tier support is there, and the docs have got your back. Happy coding!
This content originally appeared on DEV Community and was authored by Shrijith Venkatramana