今日はフェス!唐揚げにレモンはかける派で参戦します!
どーも、io チームでバックエンドやってます id:pokotyamu です!
今日は、FFLT で話した Chalice について紹介しようと思います!
Chalice とは?
Chalice とは AWS 製のサーバーレスフレームワークツールです。 似たような他のツールといえば、 Serverless Framework が一番有名かと思います。
自分は、先日行われた Serverless Conf Tokyo で初めて知りました! その時の感想やレポート記事はこちらから↓
- Serverlessconf Tokyo 2017 に参加してきました - Feedforce Developer Blog
- Serverless Conf Tokyo 2017 に行ってきたぞ - pokotyamuさんのメモ帳
特徴として、 API Gateway + AWS Lambda の構成かつ Python のみサポートというほんとに最小構成をターゲットにしています。
ただ、Chalice の中で、Dynamo DB や S3 を管理することは出来ません。 ここが Serverless Framework との大きな違いです。 GCP や Azure を対象とせずに、絞っているからこその特徴をこの記事では紹介していきます!
基本構成
新規プロジェクトの作成は以下のコマンドで行えます。
$ chalice new-project <project-name>
すると次のような構成でファイル群が作られます。
<project-name> ├── app.py └── requirements.txt 0 directories, 2 files
あとは、AWS のクレデンシャルを環境変数にセットして、 $ chalice deploy
とするだけです!
app.py
の中で、関数を定義していきます。
from chalice import Chalice app = Chalice(app_name='sample') @app.route('/') def index(): return {'hello': 'world'}
@app.route('/')
こちらが、実際のエンドポイントを作成するためのデコレーターで、http メソッドの定義もこちらで行うことが出来ます。
URL パラメーターを使いたい時は、API Gateway で作るときと同じように、{}
で囲むことで作ることができ、そのデコレートされている関数の引数とすれば、そのまま使うことが出来ます。
@app.route('/hello/{name}') def index(name): return {'hello': name }
ここがすごいぞ Chalice
エラーレスポンスのコード化
Lambda でエラーになった際に、 400 とか 403 などのエラーを最終的なレスポンスとして返したくなることはよくあると思います。
そんな時、
- API Gateway の統合レスポンスでエラーメッセージのパターンを定義してステータスコードを割り当てる
- Lambda コードで、ステータスやヘッダーを意識してコードを書いた上で、 Lambda Proxy で割り当てる
といった方法が考えられると思います。
ただ、1つ目の方法の場合、エラーメッセージが変わった時に、ビジネスロジックとパターンマッチのコードどちらも修正が必要になります。
また、2つ目の方法は、コードを書く中で API Gateway のことを意識して、エラーの組み立てを行わなければなりません。
Chalice の場合は、デフォルトで以下のエラークラスが用意されています。
* BadRequestError - return a status code of 400 * UnauthorizedError - return a status code of 401 * ForbiddenError - return a status code of 403 * NotFoundError - return a status code of 404 * ConflictError - return a status code of 409 * TooManyRequestsError - return a status code of 429 * ChaliceViewError - return a status code of 500
これらのエラークラスを raise
させるだけで、それぞれに対応したステータスコードでエラーレスポンスを行うことができるのです。
from chalice import BadRequestError CITIES_TO_STATE = { 'seattle': 'WA', 'portland': 'OR', } @app.route('/cities/{city}') def state_of_city(city): try: return {'state': CITIES_TO_STATE[city]} except KeyError: raise BadRequestError("Unknown city '%s', valid choices are: %s" % ( city, ', '.join(CITIES_TO_STATE.keys())))
$ curl {end-point}/cities/seattle {"state": "WA"} $ curl {end-point}/cities/fukuoka {"Code": "BadRequestError", "Message": "BadRequestError: Unknown city 'fukuoka', valid choices are: seattle, portland"}
これによって、エラーメッセージの変更でパターンマッチを変えて、再度デプロイし直して検証してみたいなことをする必要もありません!また、 Lambda Proxy のお約束事も特に気にする必要もありません!
素敵な未来だった👏👏👏
IAM policy 管理からの開放
AWS を使う上でわりと頭を悩ませるのが、 IAM ロールにどこまで権限を与えるか?という点です。 Admin をアタッチは基本的にアンチパターンなので、必要な分だけいい感じに Action に追加してほしい。
そんな時に Chalice では、 boto3 で使っているメソッドから自動的に必要な IAM を提示して更新してくれるという機能を持っています。
import json import boto3 from botocore.exceptions import ClientError from chalice import NotFoundError S3 = boto3.client('s3', region_name='us-west-2') BUCKET = 'your-bucket-name' @app.route('/objects/{key}', methods=['GET', 'PUT']) def s3objects(key): request = app.current_request if request.method == 'PUT': S3.put_object(Bucket=BUCKET, Key=key, Body=json.dumps(request.json_body)) elif request.method == 'GET': try: response = S3.get_object(Bucket=BUCKET, Key=key) return json.loads(response['Body'].read()) except ClientError as e: raise NotFoundError(key)
この例では、 S3 バケットに対して、 PUT
でリクエストのボディーに入っている json を書き出し。 GET
で指定したファイル名のデータを取得する関数を定義しています。
実際にデプロイしてみましょう。
$ chalice deploy Creating deployment package. The following actions will be added to the execution policy: s3:GetObject s3:PutObject Would you like to continue? [Y/n]: y Updating IAM policy for role: sample-dev Updating lambda function: sample-dev API Gateway rest API already found: xxxxxxxx Deploying to API Gateway stage: api https://{endpoint}-api.ap-northeast-1.amazonaws.com/api/
一度デプロイ時に S3 の GetObject と PutObject を追加してもいいか聞かれます。 ここで yes とすると自動的に IAM policy を更新してくれるんです!
これで悩ましい IAM policy から開放されますね!!!!
その他機能
Chalice には、他にもローカルにサーバを立てる $ chalice local
コマンド。
vendor/
に 3rd Party の Library を入れておくことで、deploy 時によしなに含めてくれる機能。(参考: chalice/packaging.rst at master · aws/chalice)
Python と API Gateway + Lambda に特化してるからこそ、デフォルトでできる機能がたくさん入っています!!
まとめ
今回 Chalice について紹介させていただきました。 ぜひ、 Python + API Gateway + Lambda でサーバーレスを試してみたいなと思われている方はお試しください!
ちなみに、僕はこの内容をスライドだけでは伝わらないと思いまして、デモすることにしました。
しかし、デモの練習用に使ってたファイルを本番でいじってしまい、全然変更が反映されない。。。なぜ。。。みたいなテンパリから、時間切れで爆死しました。 みなさんも、 LT でデモする時は、心のゆとり。たくさんの練習。無駄なアプリを起動しない。この3つを気をつけると成功すると思いますよ!
みなさんの温かい感想とともに失礼します|彡サッ