Blueprints

Chalice blueprints are used to organize your application into logical components. Using a blueprint, you define your resources and decorators in modules outside of your app.py. You then register a blueprint in your main app.py file. Blueprints support any decorator available on an application object.

Note

The Chalice blueprints are conceptually similar to Blueprints in Flask. Flask blueprints allow you to define a set of URL routes separately from the main Flask object. This concept is extended to all resources in Chalice. A Chalice blueprint can have Lambda functions, event handlers, built-in authorizers, etc. in addition to a collection of routes.

Example

In this example, we’ll create a blueprint with part of our routes defined in a separate file. First, let’s create an application:

$ chalice new-project blueprint-demo
$ cd blueprint-demo
$ mkdir chalicelib
$ touch chalicelib/__init__.py
$ touch chalicelib/blueprints.py

Next, we’ll open the chalicelib/blueprints.py file:

from chalice import Blueprint


extra_routes = Blueprint(__name__)


@extra_routes.route('/foo')
def foo():
    return {'foo': 'bar'}

The __name__ is used to denote the import path of the blueprint. This name must match the import name of the module so the function can be properly imported when running in Lambda. We’ll now import this module in our app.py and register this blueprint. We’ll also add a route in our app.py directly:

from chalice import Chalice
from chalicelib.blueprints import extra_routes

app = Chalice(app_name='blueprint-demo')
app.register_blueprint(extra_routes)


@app.route('/')
def index():
    return {'hello': 'world'}

At this point, we’ve defined two routes. One route, /, is directly defined in our app.py file. The other route, /foo is defined in chalicelib/blueprints.py. It was added to our Chalice app when we registered it via app.register_blueprint(extra_routes).

We can deploy our application to verify this works as expected:

$ chalice deploy
Creating deployment package.
Creating IAM role: blueprint-demo-dev
Creating lambda function: blueprint-demo-dev
Creating Rest API
Resources deployed:
  - Lambda ARN: arn:aws:lambda:us-west-2:1234:function:blueprint-demo-dev
  - Rest API URL: https://rest-api.execute-api.us-west-2.amazonaws.com/api/

We should now be able to request the / and /foo routes:

$ http https://rest-api.execute-api.us-west-2.amazonaws.com/api/
HTTP/1.1 200 OK
Connection: keep-alive
Content-Length: 17
Content-Type: application/json
Date: Sat, 22 Dec 2018 01:05:48 GMT
Via: 1.1 5ab5dc09da67e3ea794ec8a82992cc89.cloudfront.net (CloudFront)
X-Amz-Cf-Id: Cdsow9--fnTH5EdjkjWBMWINCCMD4nGmi4S_3iMYMK0rpc8Mpiymgw==
X-Amzn-Trace-Id: Root=1-5c1d8dec-f1ef3ee83c7c654ca7fb3a70;Sampled=0
X-Cache: Miss from cloudfront
x-amz-apigw-id: SSMc6H_yvHcFcEw=
x-amzn-RequestId: b7bd0c87-0585-11e9-90cf-59b71c1a1de1

{
    "hello": "world"
}

$ http https://rest-api.execute-api.us-west-2.amazonaws.com/api/foo
HTTP/1.1 200 OK
Connection: keep-alive
Content-Length: 13
Content-Type: application/json
Date: Sat, 22 Dec 2018 01:05:51 GMT
Via: 1.1 95b0ac620fa3a80ee590ecf1cda1c698.cloudfront.net (CloudFront)
X-Amz-Cf-Id: HX4l1BNdWvYDRXan17PFZya1vaomoJel4rP7d8_stdw2qT50v7Iybg==
X-Amzn-Trace-Id: Root=1-5c1d8def-214e7f681ff82c00fd81f37a;Sampled=0
X-Cache: Miss from cloudfront
x-amz-apigw-id: SSMdXF40vHcF-mg=
x-amzn-RequestId: b96f77bf-0585-11e9-b229-01305cd40040

{
    "foo": "bar"
}

Blueprint Registration

The app.register_blueprint function accepts two optional arguments, name_prefix and url_prefix. This allows you to register the resources in your blueprint at a certain url and name prefix. If you specify url_prefix, any routes defined in your blueprint will have the url_prefix prepended to it. If you specify the name_prefix, any Lambda functions created will have the name_prefix prepended to the resource name.

Note

The name_prefix parameter does not apply to the Lambda function associated with API Gateway, which is anything decorated with @app.route().

Advanced Example

Let’s create a more advanced example. If this application, let’s say we want to organize our application into separate modules for our API and our event sources. We can create an app with these files:

$ ls -la chalicelib/
__init__.py
api.py
events.py

The contents of api.py are:

from chalice import Blueprint


myapi = Blueprint(__name__)


@myapi.route('/')
def index():
    return {'hello': 'world'}


@myapi.route('/foo')
def index():
    return {'foo': 'bar'}

The contents of events.py are:

from chalice import Blueprint


myevents = Blueprint(__name__)


@myevents.schedule('rate(5 minutes)')
def cron(event):
    pass


@myevents.on_sns_message('MyTopic')
def handle_sns_message(event):
    pass

In our app.py we’ll register these blueprints:

from chalice import Chalice
from chalicelib.events import myevents
from chalicelib.api import myapi

app = Chalice(app_name='blueprint-demo')
app.register_blueprint(myevents)
app.register_blueprint(myapi)

Now our app.py only registers the necessary blueprints, and all our resources are defined in blueprints.

Websockets →