Write Your First AWS Lambda Function with Flask and Zappa

Write Your First AWS Lambda Function with Flask and Zappa

AWS Lambda is a "serverless computing" platform.  This means that instead of spinning up an EC2 instance, you can let Amazon dynamically allocate machine resources and then automatically spin them down after your code has executed.  Yes, there technically are servers involved, but the service totally abstracts them away so all you have to think about is your code.  Cool!

Your Lambda function is triggered by an event such as an HTTP request via Amazon API Gateway, or from a change in your DynamoDB table.  This makes Lambda a great platform for building small, on-demand applications.  As an example, we're going to deploy a "Dummy Image Generator" much like dummyimage.com, a service for creating placeholder images.  AWS Lambda pricing includes 1M requests for free every month, so you can host your function for basically nothing!

Currently, Lambda supports Node.js, Java, C# and Python.  Personally, I'm a big fan of Python and a micro web development framework called Flask.  Flask makes it super simple to define a URL path and return the result of a python function.  Its simplicity makes it a natural fit for AWS Lambda.  Here's the entire code for our Dummy Image service in just 40 lines:

Let's quickly walk through what we've done here.  First, we import the necessary libraries.  Flask provides the framework for our application.  BytesIO is a core module for Python that allows you to write a file to memory (the RAM) instead of to disk.  Since our images will be generated every time, we can just create them in memory without storing or serving them from S3.  PIL stands for "Python Imaging Library," and it allows us to create and manipulate image data.  We'll be using the ImageDraw and ImageFont modules of PIL to be able to display our image width and height within the image itself.

Our application only has one route.  The route accepts three values which get passed into our image function.  These are the desired color (a hex value), width, and height of our image.  I have included a function for converting the hex color to RGB in order to supply the Image.new function with the format it expects as input.  Next, we add the overlay text and calculate the middle of the image.  Finally, we return the file in the response, being sure to set the mime type to "image/png".  That's about it for our code, but how do we get it online?

That's where Zappa comes in.  Zappa is a command line deployment tool that makes pushing your code up to AWS super simple.  Zappa will package up both your code and your local virtual environment and format it as a Lambda compatible archive.  It replaces any dependencies with ones that have already been precompiled on Lambda, uploads your code, configures API Gateway with WSGI compatible routes, and manages the IAM permission settings.  With a couple of keystrokes you're live.  It's like magic!

Here are the steps to get your own function online.

1.  Sign up for Amazon Web Services and enable Lambda services

2.  Save the code above in a file called dummyImage/app.py

3. Create a virtual environment

$ mkvirtualenv myfirstlambda

4.  Install the libraries with pip

$ pip install flask
$ pip install pillow
$ pip install zappa

5. Initialize zappa to create your configuration file

$ zappa init

6. Enter the deployment settings, or just use all of the default settings Zappa suggests.  If you say "no" to deploying your function globally, then you'll need to edit the zappa_settings.json file that the tool creates, and change the "aws_region" value to a valid region such as "us-east-1" before your run the deploy command.

7. Run the deploy command

$ zappa deploy

If Zappa completes its job successfully, you'll get a message that says "Deployment Complete!" along with the URL to your function!  All that's left to do is to see it works by appending your image options to the route.


Congratulations!  What functions will you create?  Here are some great examples that other people have come up with.