【API Gateway】AWS Lambda統合のPythonでHello, world


Amazon API GatewayからPythonで書いたAWS Lambdaを起動してみたい、と思ってやってみました。
[公式ドキュメント](https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/api-gateway-create-api-as-simple-proxy-for-lambda.html#api-gateway-proxy-integration-create-lambda-backend) では、Pythonのコード例がなかったので、備忘録的に書いてみます。

# 手順

## AWS Lambda関数の作成

1. AWSコンソールにサインインして、[サービス]→[AWS Lambda]を選択。
1. 関数一覧画面が表示されるので、右上の「関数の作成」ボタンをクリック。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/122210/ecda13d7-9b9f-59e7-25ee-786329e8fa41.png)

1. 「一から作成」を選択し、以下のように入力
    * 名前：hello-world-python
    * ランタイム：Python 3.6
    * ロール：テンプレートから新しいロールを作成
    * ロール名:hello-world-python-role
    * ポリシーテンプレート:テストハーネスのアクセス権限
![image.png](https://qiita-image-store.s3.amazonaws.com/0/122210/479ae371-5abe-87f4-5f3d-73a49e598698.png)
1. 入力したら「関数の作成」ボタンをクリック。 すると、以下のような関数のデザイン画面に切り替わります。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/122210/da1f0af2-84ad-f3ac-65df-e992f177b8a2.png)

## AWS Lambda関数のトリガーを設定

この状態では、作成したAWS Lambda関数を実行するきっかけとなるトリガーがありません。  
今回はAPI Gatewayから呼び出したいので、Designerパネルの「トリガーの追加」の下の「API Gateway」をクリックします。

すると、「トリガーの設定」という項目がDesignerパネルの下に現れるので、以下のように設定します。

* API：新規APIの作成
* API名：LambdaHelloPython
* デプロイされるステージ:dev
* セキュリティ：オープン
![image.png](https://qiita-image-store.s3.amazonaws.com/0/122210/ee57f87b-9af2-6ea8-73b6-28137d6e1033.png)


入力できたら「追加」ボタンをクリックします。すると、下図のようにDesignerパネルの「API Gateway」の項目のところに「保存されていない変更」と表示されるので、一度画面右上の保存ボタンをクリックして保存しておきます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/122210/4477ce48-1a82-6c4e-0921-2d312b93fabd.png)

## AWS Lambda関数の実装

次に、PythonでAWS Lambda関数を記述します。
Designerパネルの「hello-world-python」の部分をクリックすると、Desingerパネルの下に「関数コード」パネルが表示さます。ここが簡易的なエディタになっており、直接コードを記述できます。

ここで、初期状態で入力されているコードは以下のようになっています。

```Python
def lambda_handler(event, context):
    # TODO implement
    return 'Hello from AWS Lambda'
```

このままだとAPI Gatewayが期待する戻り値と一致しないので、戻り値を以下のように修正します。

```Python
def lambda_handler(event, context):
    return {
        'isBase64Encoded': False,
        'statusCode': 200,
        'headers': {},
        'body': '{"message": "Hello from AWS Lambda"}'
    }

```

API GatewayからAWS Lambda関数を呼び出した場合、そのAWS Lambda関数は上記コード例のように、以下の4つの項目を返す必要があります（[プロキシ統合のためのAWS Lambda関数の出力形式](https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-output-format)より）。

* isBase64Encoded: `True`または`False`。`body`がバイナリの場合、Base64エンコード文字列でbodyに記述の上、この項目を`True`とします。
* statusCode: HTTPレスポンスのステータスコードを整数型で記述します。
* headers: HTTPレスポンスのヘッダーに記述したいものがあれば、ディクショナリでここに記述します。
* body: HTTPレスポンスのボディを文字列で記述します。

AWS Lambda関数のコードを変更したら画面右上の「保存」をクリックします。

## AWS Lambda関数のテスト

保存したAWS Lambda関数のコードに間違いがないかどうか、テストしましょう。「保存」ボタンのすぐ左の「テスト」ボタンをクリックします。 　
すると、「テストイベントの設定」という画面が開きますので、以下のように設定します。

* 「新しいテストイベントの作成」を選択
* イベントテンプレート：API Gateway AWS Proxy
* イベント名：APIGatewayEvent1

![image.png](https://qiita-image-store.s3.amazonaws.com/0/122210/542960ec-5bb6-6397-c8c0-8f09734e0d62.png)

設定したら、「作成」ボタンをクリックします。

「テスト」ボタンの左のコンボボックスで「APIGatewayEvent1」が選択された状態で、再度「テスト」ボタンをクリックします。  
以下の画面のように「実行結果：成功」と表示されればOKです。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/122210/f0744d02-63a1-f8b6-03fb-5e448a8b6d66.png)

エラーがあった場合は、以下のような画面となります。「ログ出力」の項目の下の点線矩形内に、コードのどこでエラーが発生したかが表示されているので、ここを参考にコードを直しましょう。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/122210/ea848e2e-a9b6-cd86-3b64-3baeb1656f97.png)

## API GatewayからAWS Lambda関数を駆動する。

ここまでできれば、次はAPI Gatewayをデプロイして、呼び出すことができます。
Designerパネルの「API Gateway」のところをクリックし、下に現れた「LambdaHelloPython」のリンクをクリックします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/122210/d5ad27fd-0edb-d5d4-ddf9-ec3e1f4e69b5.png)

すると、API Gatewayのマネジメントコンソールに移動します。先ほどAWS Lambdaの設定時に作成したAPIの設定画面が表示されます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/122210/8548a10e-7216-e20d-3679-615bdbb91d15.png)

ここで、カミナリマークの上の「テスト」と書かれた部分
![image.png](https://qiita-image-store.s3.amazonaws.com/0/122210/38806aa6-a20d-1e0c-f470-8e51a19c315b.png)
をクリックすると、以下のような画面に切り替わります。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/122210/a5dd676b-a0fa-7d87-45eb-a47eb13757d0.png)

ここで、「メソッド」に「GET」を指定し、他はそのままで、ページ最下部の「テスト」ボタンをクリックします。すると、以下のようにテスト結果がページの右側に表示されます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/122210/f7a29961-683c-c20c-fb4c-5ca80f0cc78f.png)

ページ右側の結果部分に「ステータス：200」と表示され、レスポンス本文が以下のように、AWS Lambda関数で`body`に指定した内容が表示されていればOKです。

```json
{
  "message": "Hello from AWS Lambda"
}
```

## API Gatewayのデプロイ

では、作成したAPIをデプロイして、curlで叩いてみましょう。
「アクション」と書かれたボタンをクリックし、プルダウン表示されたメニューから「APIのデプロイ」を選択します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/122210/6cb76ec7-3033-050e-e9cf-00ad36fbaff6.png)

すると、「APIのデプロイ」という画面が表示されるので、「デプロイされるステージ」に「dev」を指定して、「デプロイ」ボタンをクリックします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/122210/4058b766-1fc4-b3ee-1e09-c7b0c2471736.png)

すると、下図のような画面になり、「URLの呼び出し：」に続いてステージURLが表示されます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/122210/c0d3d9f8-dfee-3711-75a4-9fd8f696dfb2.png)

このURLの後ろに`/hello-world-python`とつけることで、作成したAPIにアクセスできます。

```sh
curl <ステージURL>/hello-world-python
```

以下のように、PythonのAWS Lambda関数が`body`で返したレスポンスが表示されればOKです。

```
{"message": "Hello from AWS Lambda"}
```

## デプロイの削除

上記手順で作ったAPIは「セキュリティ」を「オープン」に設定しているため、誰でもアクセスできてしまいます。第三者から不用意に大量にアクセスされないよう、動作確認ができたらステージを削除しておきましょう。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/122210/31c91bb5-ba1a-cf0f-3e08-52af05cffe62.png)



# まとめ

PythonコードでAWS Lambda関数を記述しました。その関数が返す値を、API Gatewayが求める形式にしました。
作成したAWS Lambda関数をAPI Gatewayから呼び出すように設定しました。
APIをデプロイし、curlで叩くことで動作を確認しました。