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:
- Binary content type support. Chalice now automatically configures support for binary payloads in Amazon API Gateway.
- Configuration options for AWS Lambda functions. You can now configure the amount of memory, the timeout, and the set of tags to apply to the Lambda function that Chalice creates.
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.