AWS Chalice とは
AWS Chaliceとは、Lambdaを中心としたサーバーレスアプリケーションを開発するためのフレームワークです。API Gatewayとの連携も自動化することができ、簡単にREST APIを開発することができます。他には、S3やSQSなどのイベントからのトリガーなど、AWS Lambdaを使う際の設定を自動化することができます。
AWS Chalice の使い方
インストール
次のコマンドでChaliceをインストールします。
$ pip install chalice
必要に応じてAWSのクレデンシャルの設定をします。
$ aws configure
helloworld
という名前のChaliceプロジェクトを作成します。
$ chalice new-project helloworld
プロジェクトの作成により次のようなファイルが生成されます。
.
├── .chalice
│ └── config.json
├── .gitignore
├── app.py
└── requirements.txt
ここで重要なのがapp.py
とconfig.json
です。app.py
はアプリケーションのロジックを記述するファイルで、config.json
はアプリケーションの設定項目を記述するファイルです。
app.py
は次のようになっています。API Gatewayのエンドポイント/
にGETメソッドでアクセスすると{'hello': 'world'}
というレスポンスを返すようになっています。
from chalice import Chalice
app = Chalice(app_name = 'helloworld')
@app.route('/')
def index():
return {'hello': 'world'}
プロジェクト作成時点でconfig.json
は次のようになっています。
{
"version": "2.0",
"app_name": "helloworld",
"stages": {
"dev": {
"api_gateway_stage": "api",
"autogen_policy": true
}
}
}
stages
では任意の環境や環境変数を設定することができます。autogen_policy
ではChaliceが自動でIAMロールを作成するかどうかを設定することができます。autogen_policy
をfalse
にする場合はiam_policy_file
に自身で作成したポリシーファイルのパスを記述します。例として次のようにconfig.json
を編集することができます。
{
"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"
}
}
}
}
ローカル実行
次のコマンドでChaliceプロジェクトをローカル実行することができます。
$ chalice local
デプロイ
次のコマンドで簡単にプロジェクトをデプロイすることができます。必要に応じて、AWSのプロフィールやconfig.json
で設定したstage
を選択することができます。
$ chalice deploy
$ chalice deploy --profile chalice
$ chalice deploy --state dev
デプロイが成功するとAWS上で次のリソースが自動で生成されます。
- IAMロール
- Lambda関数
- API Gateway
リソースを削除
デプロイしたChaliceプロジェクトを削除する場合は次のコマンドを実行します。
$ chalice delete
CORS を有効化
app.py
にcors=True
を追記することで簡単にCORS対応することができます。
@app.route('/', methods = ['GET'], cors = True)
Cognito の認証を有効化
APIへのアクセスをAWSのCognitoの認証により制限したい場合は次のようなコードを記述します。
from chalice import CognitoUserPoolAuthorizer
authorizer = CognitoUserPoolAuthorizer("MyPool", provider_arns=[POOL_ARN])
@app.route('/', methods = ['GET'], authorizer=authorizer)
そしてAPIにリクエストを投げる際にヘッダのAuthorizationに有効なCognitoのIDトークンを付与するとアクセスすることができます。
デコレータ
Chaliceではデコレータを使うことでLambdaと他のAWSサービスとの連携が可能です。パターンとして以下が挙げられます。
- 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
の分割
ChaliceでAPIの開発をしていると、プログラムの規模が大きくなるにつれてapp.py
が肥大化していき、生産性や保守性が悪くなってしまいます。解決方法の一つとして、ChaliceのBlueprintsという機能を使い、app.py
を任意の単位で分割することができます。
例えば次の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'}
これからapp.py
を分割していきます。現在のディレクトリ構成は次のようになっています。
helloworld/
├── app.py
└── requirements.txt
次のようにディレクトリを切ります。Chaliceでは自作モジュールはchalicelib
というディレクトリに格納する必要があります。
helloworld/
├── app.py
├── chalicelib
│ ├── __init__.py
│ └── blueprints
│ ├── __init__.py
│ ├── a.py
│ └── b.py
└── requirements.txt
app.py
のエンドポイントをa.py
とb.py
にそれぞれ移行します。
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'}
app.py
を次のように修正します。
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)
これでapp.py
を分割することができました!
Chalice のテスト
Chaliceはchalice.test
というテストクライアントを提供しており、Chaliceアプリケーションのテストに使用することができます。このクライアントでは、Lambda関数やイベントハンドラを直接呼び出したり、REST APIをテストしたりすることができます。
まずは次のコマンドでpytest
をインストールします。
$ pip install pytest
そして次のようにディレクトリを切ります。
helloworld/
├── app.py
├── tests
│ ├── __init__.py
│ ├── conftest.py
│ └── test_app.py
└── requirements.txt
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
test_app.py
にはpytest
のコードを書いていきます。例えば次のようなコードになります。
from chalice.test import Client
from app import app
def test_helloworld(client: Client):
response = client.http.get("/")
assert response.status_code == 200
次のコマンドでテストを実行することができます。
$ 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 ============================
参考