Serverless Framework で API Gateway を利用する
Serverless Framework で API Gateway と Lambda を使った、サーバーレスな API の作成方法について説明します。
前提
Serverless Framework がインストール済みで、AWS のアカウント設定済みの前提で進めます。
Serverless Framework のインストールがまだの場合は、こちらの記事でインストール方法などは記載していますので、そちらを確認してください。
API Gateway と接続した Lambda の設定
Serverless Framework で Lambda を起動するイベントを設定する場合は、serverless.yml のfunctions
にevents
を追加します。
このevents
部分には Lambda を起動するイベントとして、S3 の put イベントや DynamoDB Stream、CloudWatch Events など様々なイベントを設定できます。
serverless.yml の設定
今回は API Gateway をイベントとして使いたいので、以下のように設定します。
functions:
hello:
handler: handler.hello
events:
- httpApi:
path: /hello
method: get
httpApi
部分が API Gateway をイベントとして設定するという意味になります。
API Gateway では、HTTP API と REST API の 2 種類が選択できます(詳細はAWS のドキュメントを参照してください)。
HTTP API を利用したい場合はhttpApi
、REST API を利用したい場合はhttp
で設定してください。どちらを使うか悩む場合は、基本的に HTTP API の利用で問題ないです。
path
はパスパラメータ、method
は HTTP メソッドです。
今回は/hello
というパスで、GET
メソッドで取得できる API を作成するという意味になります。
Lambda のコード内容
Lambda のコードはsls create -t aws-python3
で作成したテンプレートのままですが、以下になります。
import json
def hello(event, context):
body = {
"message": "Go Serverless v1.0! Your function executed successfully!",
"input": event
}
response = {
"statusCode": 200,
"body": json.dumps(body)
}
return response
API Gateway と連携する場合、レスポンスをstatusCode
とbody
を key とした JSON 形式で返す必要があります。
statusCode
は HTTP ステータスコードのことで、正常でのレスポンスなら200
になります。
body
は実際に返す JSON データです。
AWS にデプロイ
上記の内容を AWS にデプロイします。
$ sls deploy
〜省略〜
endpoints:
GET - https://<yourapigatewayid>.execute-api.ap-northeast-1.amazonaws.com/hello
〜省略〜
デプロイを実行すると、最後の方にendpoints
というものが出力されます。これが作成された API Gateway の URL になります。
この URL に対して API を実行してみます。JSON 整形のために jq コマンドを使用していますが、これは見やすくしてるだけなので、なくても問題ありません。
<yourapigatewayid>
となっている部分は、適時自分の URL で読み替えてください。
$ curl -XGET 'https://<yourapigatewayid>.execute-api.ap-northeast-1.amazonaws.com/hello' | jq .
{
"message": "Go Serverless v1.0! Your function executed successfully!",
"input": {/*色んなデータ*/}
}
コード上のbody
の中身がレスポンスとして出力されています。
message
部分はコードに書いたままの文字列が、input
部分はevent
をそのまま渡しているので、API Gateway 特有のイベントデータがすべて出力されています。
また、クエリ文字列を渡すと、event
の中にqueryStringParameters
というパラメータが含まれるので、その値を使うことで GET パラメータを使用できます。
クエリ文字列の利用方法
API のデプロイまではできたので、API でクエリ文字列を利用する方法について説明します。
クエリ文字列を確認するために、コードをちょっと変更します。
import json
def hello(event, context):
params = event.get('queryStringParameters') # パラメータ取得
body = {
"message": "Go Serverless v1.0! Your function executed successfully!",
"input": params # パラメータのみ表示に変更
}
response = {
"statusCode": 200,
"body": json.dumps(body)
}
return response
コードの変更を反映するために、再度デプロイします。
$ sls deploy
クエリ文字列の確認
デプロイできたら、API を再実行します。
まずは、クエリなしで実行。
$ curl -XGET 'https://<yourapigatewayid>.execute-api.ap-northeast-1.amazonaws.com/hello' | jq .
{
"message": "Go Serverless v1.0! Your function executed successfully!",
"input": null
}
クエリなしなので、input の値が null で返ってきています。
次に、クエリありで実行します。param1=123¶m2=abc
というクエリを設定してリクエストします。
$ curl -XGET 'https://<yourapigatewayid>.execute-api.ap-northeast-1.amazonaws.com/hello?param1=123¶m2=abc' | jq .
{
"message": "Go Serverless v1.0! Your function executed successfully!",
"input": {
"param1": "123",
"param2": "abc"
}
}
input
の中にkey: value
の形式で値が入ってきました。
そのため、event
のqueryStringParameters
は以下のような形で入っていることがわかります。また、クエリ文字列なので、value がすべて string 型になっている点は注意してください。
{
"queryStringParameters": {
"param1": "123",
"param2": "abc"
}
}
API Gateway を利用する際の注意点
API Gateway を利用する場合、Lambda のタイムアウト設定に注意してください。
現時点の仕様だと Lambda のタイムアウトは最大 15 分まで設定可能ですが、API Gateway のタイムアウトは最大 30 秒になっています。HTTP API は 30 秒固定、REST API は最大 29 秒で設定可能です。詳細はAWS のマニュアルを確認してください。
そのため、Lambda のタイムアウト値は API Gateway のタイムアウト以下に設定してください。
Lambda のタイムアウト値が API Gateway のタイムアウトより長い場合、API のレスポンスはタイムアウトなのに Lambda 自体は正常終了することがあるためです。
Lambda での処理が長時間かかるような場合、API のレスポンスは即時で返して、それとは別に非同期で結果を連携する仕組みなどを考える必要があります。
おまけ
今回使用したコードは以下の Github リポジトリにアップしているので、全体のコードを確認したい方はそちらを見てください(v2.0 のタグが今回のコードです)。
Discussion