AWS Developer Tools Blog

Chalice Version 0.9.0 is Now Available

The latest preview version of Chalice, our microframework for Python serverless application development, is now available. This release includes a couple of commonly requested features:

To demonstrate these features, let’s walk through a sample Chalice app.

Thumbnail Generator

In this sample app, we create a view function that accepts a .png file as input, and generates a thumbnail of the image as output. This requires accepting binary content in the request body and returning binary content in the response body.

First, we install Chalice and create our initial project structure.

$ virtualenv /tmp/venv
$ source /tmp/venv/bin/activate
$ pip install chalice
$ chalice new-project thumbnail-generator
$ cd thumbnail-generator

Next, we write a view function that expects an image as the request body. It then produces a thumbnail of that image and sends it as a response. Here’s the code to do this.

from io import BytesIO
from chalice import Chalice, Response

from PIL import Image

app = Chalice(app_name='thumbnail-generator')


@app.route('/thumbnail', content_types=['image/png'], methods=['POST'])
def thumbnail():
    im = Image.open(BytesIO(app.current_request.raw_body))
    im.thumbnail((150, 150))
    out = BytesIO()
    im.save(out, 'PNG')
    return Response(out.getvalue(),
                    status_code=200,
                    headers={'Content-Type': 'image/png'})

To properly handle incoming binary content, we need two elements. First, we must declare the content type we’re expecting as input using the content_types argument in the route() call. By specifying content_types=['image/png'], we state that requests must set the Content-Type header to image/png. Second, to access the raw binary request body, we must use the app.current_request.raw_body attribute. This is the raw binary data that we will load with
Pillow, the python imaging library we’ll use to generate thumbnails.

Once we’ve used Pillow to generate a thumbnail, we must return the generated image as binary content. To do so, we use the Response` class. To return binary content, we again need two elements.

First, the response body we pass to the Response object must be of type bytes(). Second, we must specify a Content-Type header that is configured as a binary content type. By default, Chalice automatically configures a common set of content types as binary. Therefore, in most cases you only have to set the appropriate content type. You can see the list of default binary content types here
<http://chalice.readthedocs.io/en/latest/api.html#default_binary_types>__. If a binary content type you want to use isn’t in this list by default, you can change the binary content type list by modifying the app.api.binary_types list.

Before deploying, let’s test this locally. First, we install the Pillow library:

$ pip install Pillow

Next, we run chalice local and test our app using a local .png file we saved in /tmp.

$ chalice local
Serving on localhost:8000

$  curl -H 'Accept: image/png' -H 'Content-Type: image/png' \
    --data-binary @/tmp/lion.png \
    http://localhost:8000/thumbnail > /tmp/thumbnail.png

You can open /tmp/thumbnail.png and verify that a thumbnail was created.

In this example, we must set the Accept header to indicate that we want to return the binary content of type image/png.

Deploying Our App

Now that we tested the app locally, let’s deploy it to API Gateway and Lambda.

We use a couple of additional Chalice features to deploy our application. First, we configure the amount of memory to allocate to our Lambda function. This feature was just released in Chalice version 0.9.0. We want to increase the memory size of our Lambda function to 1GB. To do this, we update our .chalice/config.json file with the following lambda_memory_size entry:

$ cat .chalice/config.json
{
  "lambda_memory_size": 1024,
  "stages": {
    "dev": {
      "api_gateway_stage": "dev"
    }
  },
  "version": "2.0",
  "app_name": "thumbnail-generator"
}

We increase the amount of memory so that we have more CPU power available for our thumbnail generator. In the Lambda resource model, you choose the amount of memory you want for your function, and are allocated proportional CPU power and other resources. For example, choosing 256MB of memory allocates approximately twice as much CPU power to your Lambda function as requesting 128MB of memory.

Next, we need to install Pillow. Pillow contains C extensions that must be compatible with the platform where you run the Lambda function.

Create a vendor/ directory at the root of your application, as follow.

$ mkdir vendor

Next, download the Pillow wheel file for Linux:

$ cd vendor
$ pip download --platform manylinux1_x86_64 \
    --python-version 27 --implementation cp \
    --abi cp27mu --only-binary=:all: Pillow
$ unzip Pillow*
$ rm *.whl
$ cd ..

If you get an error about being unable to find the olefile package, you can safely ignore it. You can read more about how the vendor/ directory works in our documentation.

Now we can deploy the app using the chalice deploy command.

$ chalice deploy
Initial creation of lambda function.
Creating role
Creating deployment package.
Initiating first time deployment...
Deploying to: dev
https://abcd.execute-api.us-west-2.amazonaws.com/dev/

Let’s test it. We can use the same curl command we used previously, but replace it with our newly created remote endpoint.

$ curl -H 'Accept: image/png' -H 'Content-Type: image/png' \
    --data-binary @/tmp/lion.png \
    https://y5d036o2mf.execute-api.us-west-2.amazonaws.com/dev/thumbnail \
    > /tmp/thumbnail2.png

You can open /tmp/thumbnail2.png and verify that Chalice correctly generated a thumbnail.

Try out the latest version of Chalice today and let us know what you think. You can chat with us on our gitter channel and file feature requests on our github repo We look forward to your feedback and suggestions.