What is AWS Chalice
AWS Chalice is a framework for developing serverless applications centered on Lambda, which can also automate integration with API Gateway, making it easy to develop REST APIs. It can also automate settings for using AWS Lambda, such as triggering from events such as S3 and SQS.
How to use AWS Chalice
Installation
Install Chalice with the following command.
$ pip install chalice
Set up AWS credentials as needed.
$ aws configure
Create a Chalice project named helloworld
.
$ chalice new-project helloworld
The following files are generated by the creation of a project.
.
├── .chalice
│ └── config.json
├── .gitignore
├── app.py
└── requirements.txt
The important files here are app.py
and config.json
. The app.py
file describes the logic of the application, and the config.json
file describes the configuration items of the application.
The app.py
is as follows: accessing the API Gateway endpoint /
with the GET method returns the response {'hello': 'world'}
.
from chalice import Chalice
app = Chalice(app_name = 'helloworld')
@app.route('/')
def index():
return {'hello': 'world'}
At the time of project creation, config.json
looks like following
{
"version": "2.0",
"app_name": "helloworld",
"stages": {
"dev": {
"api_gateway_stage": "api",
"autogen_policy": true
}
}
}
In stages
you can set any environment or environment variable. In autogen_policy
you can set whether Chalice will automatically create IAM roles. If you set autogen_policy
to false
, you can set iam_policy_file
to the path of the policy file you created. As an example, you can edit config.json
as follows
{
"version": "2.0",
"app_name": "helloworld",
"autogen_policy": false,
"iam_policy_file": "custom-policy.json",
"stages": {
"dev": {
"api_gateway_stage": "dev",
"environment_variables": {
"ENV": "dev"
}
},
"prod": {
"api_gateway_stage": "prod",
"environment_variables": {
"ENV": "prod"
}
}
}
}
Local execution
You can execute the Chalice project locally with the following command.
$ chalice local
Deploy
You can easily deploy your project with the following command. If necessary, you can select an AWS profile or a stage
configured in config.json
.
$ chalice deploy
$ chalice deploy --profile chalice
$ chalice deploy --state dev
After successful deployment, the following resources will be automatically created on AWS.
- IAM role
- Lambda function
- API Gateway
Delete resources
To delete the deployed Chalice project, execute the following command.
$ chalice delete
Enable CORS
You can easily enable CORS by adding cors=True
to app.py
.
@app.route('/', methods = ['GET'], cors = True)
Enable Cognito authentication
If you want to restrict access to the API by AWS Cognito authentication, write the following code.
from chalice import CognitoUserPoolAuthorizer
authorizer = CognitoUserPoolAuthorizer("MyPool", provider_arns=[POOL_ARN])
@app.route('/', methods = ['GET'], authorizer=authorizer)
Then, when you submit a request to the API, you can access it by adding a valid Cognito ID token to the Authorization header.
Decorators
Chalice can use decorators to integrate Lambda with other AWS services. Patterns include
- AWS Lambda:
@app.lambda_function
- AWS Lambda + API Gateway :
@app.route
- AWS Lambda + Amazon CloudWatch Events:
@app.schedule
- AWS Lambda + Amazon S3:
@app.on_s3_event
- AWS Lambda + Amazon SQS:
@app.on_sqs_message
- AWS Lambda + Amazon SNS:
@app.on_sns_message
app.py
Splitting When developing APIs in Chalice, app.py
becomes bloated as the size of the program grows, leading to poor productivity and maintainability. One solution is to use Chalice's Blueprints feature, which allows you to split app.py
into arbitrary units.
For example, suppose you have the following app.py
.
from chalice import Chalice
app = Chalice(app_name='helloworld')
@app.route('/a')
def a():
return {'hello': 'a'}
@app.route('/b')
def b():
return {'hello': 'b'}
Now app.py
will be separate. The current directory structure is as follows.
helloworld/
├── app.py
└── requirements.txt
Cut the directory as follows: Chalice requires home-made modules to be stored in a directory named chalicelib
.
helloworld/
├── app.py
├── chalicelib
│ ├── __init__.py
│ └── blueprints
│ ├── __init__.py
│ ├── a.py
│ └── b.py
└── requirements.txt
Migrate the endpoints of app.py
to a.py
and b.py
respectively.
from chalice import Blueprint
extra_routes = Blueprint(__name__)
@extra_routes.route('/a')
def a():
return {'hello': 'a'}
from chalice import Blueprint
extra_routes = Blueprint(__name__)
@extra_routes.route('/b')
def b():
return {'hello': 'b'}
Modify app.py
as follows
from chalice import Chalice
from chalicelib.blueprints.a import extra_routes as a # 追加
from chalicelib.blueprints.b import extra_routes as b # 追加
app = Chalice(app_name='helloworld')
app.register_blueprint(a)
app.register_blueprint(b)
Now we can split app.py
!
Chalice Testing
Chalice provides a test client called chalice.test
that can be used to test Chalice applications. With this client, you can directly call Lambda functions and event handlers, as well as test the REST API.
First, install pytest
with the following command.
$ pip install pytest
Then cut the directory as follows
helloworld/
├── app.py
├── tests
│ ├── __init__.py
│ ├── conftest.py
│ └── test_app.py
└── requirements.txt
Put the following code in conftest.py
.
from typing import Generator
import pytest
from app import app
from chalice.test import Client
@pytest.fixture(scope="module")
def client() -> Generator:
with Client(app) as c:
yield c
In test_app.py
, you will write the code for pytest
. For example, the code would be as follows.
from chalice.test import Client
from app import app
def test_helloworld(client: Client):
response = client.http.get("/")
assert response.status_code == 200
You can run the test with the following command
$ py.test tests/test_app.py
========================= test session starts ==========================
platform darwin -- Python 3.7.3, pytest-5.3.1, py-1.5.3, pluggy-0.12.0
rootdir: /tmp/testclient
plugins: hypothesis-4.43.1, cov-2.8.1
collected 2 items
test_app.py .. [100%]
========================= 2 passed in 0.32s ============================
References