「ほぼPythonだけでサーバーレスアプリをつくろう」の3章を完了したのでその内容を紹介します。
お手本どおりやればそれほど難しくないよ。
AWSも積極的に見て行こう。
ただし、AWSはリージョンの概念があるから注意!
いつの間にか別リージョン(オハイオ)を見てたりするからね。
Amazon
第3章 ChaliceでWeb APIを作ろう
全章から見た第3章の目的
この本では、ToDoアプリを作ることをゴールとしています。
3章ではToDoアプリのバックエンド操作(追加、参照、更新、削除)のためのWeb APIを作ることです。
第3章の内容
自分のパソコン内に作成した仮想環境(バックエンド環境)に、Chaliceにてプロジェクトを作成し、それをAWSにデプロイして動かしてみるという内容です。
また、毎回 AWSを使うのではなくローカル環境でも動作するようにします。
- Chaliceでバックエンド環境新しいプロジェクトを作る
- プロジェクトをAWSにデプロイする
- プロジェクトをローカル環境にデプロイする
- プロジェクトをカスタマイズしてDBから情報を取得する
- DBから情報が取れなかった場合のエラー処理を組み込む
第3章で実際に行った詳細内容
バックエンド環境にプロジェクトを作成する
パソコン内の仮想環境(バックエンド環境)を有効にして、chalice new-project コマンドでプロジェクトを作成します。
(hobopy-backend) > chalice new-project hobopy-backend
これで、バックエンド操作のためのWeb APIを実現する Chaliceプロジェクトのファイルができます。
それぞれのファイルの役割は以下のとおりです。
①.chalice\config.json … Chaliceプロジェクトの設定ファイル
②app.py … プロジェクトのメインファイル
③.gitignore … Gitのトラッキング対象から除外するファイル
④requirments.txt … プロジェクトが依存しているパッケージ一覧
①、②だけさらっと見ておきましょう。
プロジェクトの設定ファイル(.chalice\config.json)
アプリデプロイ時に利用されるアプリ名やステージ(実行環境)の設定を記載できるようになっています。
{
"version": "2.0",
"app_name": "hobopy-backend",
"stages": {
"dev": {
"api_gateway_stage": "api"
}
}
}
テストするときはローカル環境にデプロイ、本番化するときはAWSにデプロイ、といったことを分ける際に便利です。
プロジェクトのメインファイル(app.py)
このファイルにAPIの処理を実装していきます。
初期状態では、Hello world を出力する処理になっています。
from chalice import Chalice
app = Chalice(app_name='hobopy-backend') #①
@app.route('/') #②
def index():
return {'hello': 'world'} #③
① Chaliceのインスタンスを作成
② routeデコレータで index() を修飾
アプリのURLルートにアクセスした際に index()が呼び出されます。
③ index() の戻り値です。
プロジェクトをAWSにデプロイする
作ったプロジェクトをAWSにデプロイして、AWS環境で動作することを確認しましょう。
chalice deploy コマンドでデプロイします。
(hobopy-backend) > cd hobopy-backend
(hobopy-backend) > chalice deploy --stage dev
Creating deployment package.
Creating IAM role: hobopy-backend-dev
Creating lambda function: hobopy-backend-dev
Creating Rest API
Resources deployed:
- Lambda ARN: arn:aws:lambda:ap-northeast-1:xxxxxx:function:hobopy-backend-dev
- Rest API URL: https://xxxxx.execute-api.ap-northeast-1.amazonaws.com/api/
AWSへのデプロイが完了し、Rest API URL が表示されます。
このURLにアクセスしたらちゃんと応答が返ってきますね!
(参考)デプロイするとAWS側では何が起こっているか
以下①②③の処理が1コマンドで行われていました。
これがChaliceでデプロイする手軽さなのでしょうね!
① プログラムの実行に必要となるIAMロールの作成
IAMのロールが作成されています。
② 実際の処理を行う Lambda関数の作成
AWS Lambdaに関数が作成されています。
③ API Gatewayのエンドポイントの作成
API GatewayにAPIが作成されています。
AWSからデプロイしたプロジェクトを削除する
そのままにしておいても良いですが、AWS上のサービスを使うには費用がかかります。そのため、本番化するまでは、名残惜しいですがAWSへデプロイしたプロジェクトは削除しておきましょう。
chalice delete コマンドを実行します。
(hobopy-backend) > chalice delete
Deleting Rest API: xxxxx
Deleting function: arn:aws:lambda:ap-northeast-1:3xxx:function:hobopy-backend-dev
Deleting IAM role: hobopy-backend-dev
このコマンド一つで、先ほどデプロイしたプロジェクトはAWSから消えました。
ローカル環境でプロジェクトを実行する
テスト段階はできるだけローカル環境でプロジェクトを実行しテストをしたいものです。これも chalice local コマンド一つで可能です。
(hobopy-backend) > chalice local --stage dev
Serving on http://127.0.0.1:8000
これで、ローカル環境(http://127.0.0.1:8000)で応答を受け付けるプロジェクトが動きました。実際にアクセスしてみましょう。
ローカル環境でも、AWSと同様にレスポンスが返ってきましたね!
モジュールの分割について
Chaliceによる開発では app.pyにAPI処理を実装するのですが、chalicelibフォルダ内のファイルも同じパッケージとして一緒にデプロイされる仕組みです。
つまり、app.py にすべてプログラミングを書くのじゃなく、分けましょうというということが説明されていました。
この本では、データベースへの接続部分を chalicelib\database.py に分割します。
プロジェクトにデータベースから値参照を組み込む
流れはこうです。
①データベースを操作するモジュール(database.py)作成
②メインモジュール(app.py)から①を呼び出すためのコード追加
データベースを操作するモジュール(databae.py)作成
chalicelib\database.pyを作成します。
まだ参照先のデータベースがないので、コード内でデータベース情報を直書きしています。あとは、データベース内のレコードを取得するメソッドですね。
# ①デモのため疑似データベースを定義する
DEMO_DB = [
{
'id': 'L5',
'title': 'Moso',
'memo': 'もきゅん',
'priority': 3,
'completed': False,
},
{
'id': 'L6',
'title': 'Meso',
'memo': 'もきゅー',
'priority': 2,
'completed': False,
},
{
'id': 'L7',
'title': 'Mofu',
'memo': 'もふー',
'priority': 1,
'completed': False,
}
]
# ②すべてのレコードを取得する
def get_all_todos():
return DEMO_DB
# ③指定されたIDのレコードを取得する
def get_todo(todo_id):
for todo in DEMO_DB:
if todo['id'] == todo_id:
return todo
return None
メインモジュール(app.py)にデータベース参照コード追加
app.py を修正します。先に作成したデータベース参照のためのモジュールを importで呼び出し、メソッドでデータベース参照し値を返すようにしています。
from chalice import Chalice
from chalicelib import database
app = Chalice(app_name='hobopy-backend')
# ①すべてのToDoを取得する
@app.route('/todos', methods=['GET'])
def get_all_todos():
return database.get_all_todos()
# ②指定されたIDのToDoを取得する
@app.route('/todos/{todo_id}', methods=['GET'])
def get_todo(todo_id):
return database.get_todo(todo_id)
httpレスポンスが返ってくるか、コマンドプロンプトからテスト。
ちゃんとURLで指定したとおり動作してくれた。
エラーを処理する
想定いていないリクエスに対してエラーを返すプログラムを app.py に追加しました。このような配慮も重要ですね。
# ① NotFoundErrorをimport
from chalice import Chalice, NotFoundError
# <略>
# ②指定されたIDがあればToDo返す、なければエラー(404)を返す
@app.route('/todos/{todo_id}', methods=['GET'])
def get_todo(todo_id):
todo = database.get_todo(todo_id)
if todo:
return todo
else:
raise NotFoundError('Todo not found.')
存在しないキーを指定すると、ちゃんとエラーを返してくれています。
Webサーバ側でもエラー(404)を返していることが確認できました。
第3章の所要時間
1時間30分程でした。
バックエンドの処理だけのため、また、データベース参照部分を直書きにしているので複雑でなく早く進められたと思います。
第3章を終えての感想
まだ3章ですが、実際にレスポンスが返ってくるのは思いのほか感動しますね。
感覚ですが、JavaでWebシステムを実装する際の Spring Bootフレームワークに似ていると思いました。Web APIってこういう書き方が普通なのかな~。
Web API作っちゃったわー、と天狗にならないよう気を引き締めていきましょう。
コメント