How to run Python Flask application in AWS Lambda

Flask in AWS Lambda
Flask in AWS Lambda

In this article, we'll learn how to run a Python Flask application in AWS Lambda. For those who don't know what Flask is - it is a micro-framework written in Python.

💡
TLDR: You can use the aws-wsgi python package to interface between Flask application and Lambda function and you may have to package this lambda function separately.

Why do we run Flask in AWS Lambda?

If you use AWS Lambda, you'll be billed only for the time your function is executed.  And, AWS Lambda has excellent integration with other AWS services such as DynamoDB, SQS, and others. So, if your solution is hosted in AWS - AWS Lambda is a great option to consider.

What problem do we face when we run Flask in AWS Lambda?

Flask is a framework for building web applications and APIs. AWS Lambda is a serverless computing platform that would usually runs when a particular event is fired - it could be from API Gateway, SQS, S3, or any of the many other supported services in AWS.

Flask application is meant to run for a long period of time and is always kept alive whereas Lambda is meant to run only for a short period of time and their respective interface and how they work are different.

Running Flask in AWS Lambda

There is a python package aws-wsgi which provides WSGI-compatible middleware like Flask to work with AWS API Gateway/Proxy Integration.

We can install this Python package to route the request coming to AWS API Gateway to the lambda function using Lambda integration. This lambda function would act as a wrapper for the Flask application.

Creating AWS CDK application

I'm going to create a simple AWS CDK stack in Python to create a lambda function and flask application. If you're new to AWS CDK, I've written a detailed step-by-step guide on AWS CDK here. I've explained the benefits and how to start on AWS CDK in that article.

You can create a CDK application by executing the below commands in your terminal.

mkdir aws-cdk-flask
cd aws-cdk-flask
cdk init app -l python

Creating a simple Flask application

For the sake of simplicity, I'm going to create a simple Flask application with just 1 endpoint - which would return "Hello Flask!"

from flask import (
    Flask,
    jsonify,
)

app = Flask(__name__)


@app.route('/')
def index():
    return jsonify(status=200, message='Hello Flask!')

As you can see - there is nothing special in the above code snippet. It is just a "Hello world" version of the Flask application.

Interface Flask application with AWS Lambda

Now, we need to import awsgi and use that to interface with the AWS Lambda function as shown below. Essentially, we just forward the requests from lambda to flask application with the help of awsgi.

import awsgi

def handler(event, context):
    return awsgi.response(app, event, context)

Below is the complete code for lambda_handler.py - which is inside the lambdas directory.

import awsgi
from flask import (
    Flask,
    jsonify,
)

app = Flask(__name__)


@app.route('/')
def index():
    return jsonify(status=200, message='Hello Flask!')


def handler(event, context):
    return awsgi.response(app, event, context)

Separate requirements.txt file

When you create AWS CDK an application, you'll have requirements.txt in the root folder. That requirements.txt is for creating a CDK stack.

You need to create a separate requirements.txt file in the same lambdas folder to include all the dependencies for this lambda function.

Below are the contents of the requirements.txt file that we've used for this lambda function.

aws-wsgi
flask

One important thing to note here is that packaging of this lambda function will be done separately using docker. You may need to have docker installed on your machine.

CDK Stack

In the AWS CDK stack, we create the following

  • Rest API
  • Lambda function - referring to the lambda that we've created earlier
  • Mapping ANY method to route all requests to the lambda function

Creating Rest API

We're using RestApi CDK construct - we just give the name of the api name

api = RestApi(self, "flask-api", rest_api_name="flask-api")

Creating lambda function

We're going to install aws_lambda_python_alpha python package to have this python function package separately.

 flask_lambda = _lambda_python.PythonFunction(
            self,
            "lambda_handler",
            function_name="flask-lambda",
            entry="lambdas",
            index="lambda_handler.py",
            handler="handler",
            runtime=_lambda.Runtime.PYTHON_3_8,
            timeout = Duration.seconds(30),
        )

Mapping ANY method from the API Gateway to Lambda function

Get the root of the API resource and map ANY method to lambda integration

root_resource = api.root

        any_method = root_resource.add_method(
            "ANY",
            LambdaIntegration(flask_lambda)
        )

Below is the complete code for the stack

from aws_cdk import (
    Duration,
    Stack,
    aws_lambda as _lambda,
    aws_lambda_python_alpha as _lambda_python,
)
from aws_cdk.aws_apigateway import (
    LambdaIntegration,
    RestApi,
)
from constructs import Construct

class AwsCdkFlaskStack(Stack):

    def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)

        api = RestApi(self, "flask-api", rest_api_name="flask-api")


        flask_lambda = _lambda_python.PythonFunction(
            self,
            "lambda_handler",
            function_name="flask-lambda",
            entry="lambdas",
            index="lambda_handler.py",
            handler="handler",
            runtime=_lambda.Runtime.PYTHON_3_8,
            timeout = Duration.seconds(30),
        )
        
        root_resource = api.root

        any_method = root_resource.add_method(
            "ANY",
            LambdaIntegration(flask_lambda)
        )

When you run cdk deploy to deploy the stack - all the necessary resources would be created

When you access the API Gateway, you can see the response from Flask application.

Please let me know your thoughts in the comments.