Django REST API on AWS Lambda + API Gateway HTTP API + DynamoDB, with a Tailwind + Alpine.js UI served from the same Lambda.
The Django app stays framework-pure: mangum provides the ASGI → Lambda
adapter. State lives in DynamoDB via boto3 (no ORM).
This is the Python reference for the W5 "Bring Your Own Language" challenge.
- Python 3.12 on AWS Lambda (arm64)
- Django 5 + Django REST Framework
- Mangum (ASGI → Lambda)
- API Gateway HTTP API (
PayloadFormatVersion: 2.0) - DynamoDB,
PAY_PER_REQUEST - Tailwind + Alpine.js UI (CDN, no build)
- Python 3.11+
- AWS credentials with permission for CloudFormation, Lambda, API Gateway, DynamoDB, IAM, Logs
- Docker (only if you want to run
sam local invoke)
./scripts/00-setup.sh # create .venv, install deps + SAM CLI
./scripts/01-smoke.sh # local moto-mocked smoke test
./scripts/02-deploy.sh # build + deploy to AWS
./scripts/03-test.sh # curl the API + verify DynamoDB persistence
./scripts/04-destroy.sh # tear downAfter 02-deploy.sh finishes, open the ApiUrl it prints in a browser to
use the UI.
todo_api/
├── manage.py
├── config/
│ ├── settings.py
│ ├── urls.py
│ ├── asgi.py
│ └── handler.py Mangum entrypoint
└── todos/
├── store.py boto3 DynamoDB layer
├── views.py
├── serializers.py
├── urls.py
└── templates/todos/
└── index.html single-page UI
events/ API GW v2 sample events for sam local invoke
scripts/ numbered build / deploy / test / teardown
template.yaml SAM template
samconfig.toml
requirements.txt
requirements-dev.txt
test_lambda_handler.py moto-mocked end-to-end test
| Method | Path | Notes |
|---|---|---|
| GET | / |
HTML UI |
| GET | /healthz |
{"ok": true} |
| GET | /api/todos/ |
Paginated list. Query: limit, cursor |
| POST | /api/todos/ |
Body: {"title": str, "done": bool} |
| GET | /api/todos/<id>/ |
|
| PATCH | /api/todos/<id>/ |
Partial update |
| DELETE | /api/todos/<id>/ |
204 on success |
Pagination response shape:
{
"items": [...],
"next_cursor": "base64-or-null"
}Pass next_cursor back as cursor to get the next page.
Defaults to us-west-2. Override in samconfig.toml and scripts/_lib.sh.
.venv/bin/python test_lambda_handler.pyUses moto to mock DynamoDB in-memory and invokes the Lambda handler with
synthetic API Gateway v2 events.
Measured on M-series Mac, Python 3.12, arm64, 1024 MB:
| Endpoint | Cold start | Warm |
|---|---|---|
/healthz |
~1.4-1.6 s | 5-20 ms |
/api/todos/ |
~1.4-1.6 s | 10-30 ms |