Serving Dynamic Web Pages using Python and AWS Lambda
--
While AWS Lambda functions are typically used to build API endpoints, at their core Lambda functions can return almost anything. This includes returning html markup with dynamic content.
I will not go into details describing how to deploy AWS Lambda functions. Please see the official documentation. I will however describe how to return dynamic html content instead of a typical JSON.
Step 0 — Optional
If you prefer to develop and test lambda functions locally (as I do), you can use Docker to simulate the AWS lambda function environment. A sample Dockerfile I use is below.
FROM amazonlinux:latest
RUN mkdir -p /mnt/app
ADD . /mnt/app
WORKDIR /mnt/app
RUN yum update -y
RUN yum install gcc -y
RUN yum install gcc-c++ -y
RUN yum install findutils -y
RUN yum install zip -y
RUN amazon-linux-extras install python3=3.6.2
RUN pip3 install --upgrade pip
RUN pip3 install -r requirements.txt -t aws_layer/python
The requirements.txt includes just one package for simplicity. It is the common templating for Python called Jinja2
Jinja2==2.11.1
You can test your Lambda function by simple calling it with sample parameters:
import lambda_function
event = {
"queryStringParameters": {
"param1": "value1"
},
"path": "/api",
"requestContext": {
"param2": "value2"
}
}
res = lambda_function.lambda_handler(event=event, context={})
assert 200 == int(res["statusCode"])
Step 1 — Write html template
In this step, we write the html template the Lambda function will return. A good default is the new Bootstrap 5 CSS framework where the recommended starting markup looks something like this:
Saving this file in folder “templates” and naming it index.html, we are ready to write the Lambda function.
Step 2 — Write Lambda function to serve your html page
In the example below, the lambda function expects URL parameters and parses those. So when parsing a custom URL, the format would look something like this: Example.com/?my_name=somename. See step 10 in this tutorial to add custom URLs to your API Gateway-triggered Lambda functions.
import os
import sys
from jinja2 import Environment, FileSystemLoaderdef lambda_handler(event, context):
env = Environment(loader=FileSystemLoader(os.path.join(os.path.dirname(__file__), "templates"), encoding="utf8"))
my_name = False
if event["queryStringParameters"] and "my_name" in event["queryStringParameters"]:
my_name_query = event["queryStringParameters"]["my_name"]
template = env.get_template("index.html")
html = template.render(
my_name=my_name_query
)
return response(html)def response(myhtml):
return {
"statusCode": 200,
"body": myhtml,
"headers": {
"Content-Type": "text/html",
}
}
- jinja2 loads your previously created index.html using class “FileSystemLoader” and we store it as variable “env”
- variable “my_name” is parsed from the URL query parameters as explained above and stored as the Python variable my_name_query
- the jinja2 render function then passes my_name_query to the template and returns the html page
Also published on adamnovotny.com