AWS CLIで Web サイトを構築、管理、運用する(24日目)

24 日目！
世の中はクリスマスイブ！
ということで、今日は、API Gateway から、昨日作った AWS Lambda 関数をつなぎます。
もちろん、AWS CLIで。

# 24日目の要約
API！

# AWS CLI の準備
このあたりをみて、好きなバージョンとお使いのOSにあった環境設定をしてくださいね。
なんなら、 AWS CloudShell で実行するのも楽でよいと思います。
この記事シリーズは、AWS CloudShell で実行し、実行例を載せています。

バージョン１
https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/install-cliv1.html

バージョン２
https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/install-cliv2.html

# 概要
API Gateway を作って、リクエストを受けたら Lambda 関数に処理させます。

# さあ、やってみよう！
今回は API Gateway の REST API を作っていきます。
API Gateway の各要素を以下の図で確認します。 

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/344161/d5a1b291-5937-508d-a73d-5177b7faa88b.png)

## API を作成する
まずは、APIそのものを作成します。今回は REST API を作成するので、```apigateway create-rest-api``` コマンドを実行します。

```sh
aws apigateway create-rest-api --name adventcalendar2021
```

APIの作成に成功すると、以下のような json が返るので id の値を確認しておきます。

```json
{
    "id": "u8********",
    "name": "adventcalendar2021",
    "createdDate": "2021-12-23T16:08:10+00:00",
    "apiKeySource": "HEADER",
    "endpointConfiguration": {
        "types": [
            "EDGE"
        ]
    },
    "disableExecuteApiEndpoint": false
}
```

今回はリソースを作らない(デフォルトで作られる"/"を使う)ので、"/" の ID を確認しておきます。```apigateway get-resources``` コマンドを実行します。

```sh
aws apigateway get-resources --rest-api-id <API の ID>
```

無事に取得できると、以下のような json が返るので id を確認しておきます。
この id は リソースの ID です。

```json
{
    "items": [
        {
            "id": "g8********",
            "path": "/"
        }
    ]
}
```

## GET メソッドリクエストを定義する
ここからは、各要素を順々に作っていきます。
一つ目は、クライアントからのリクエストを受け付けるための GET メソッドを ```apigateway put-method``` コマンドで作っていきます。

```sh
aws apigateway put-method \
  --rest-api-id <API の ID> \
  --resource-id <リソース のID> \
  --http-method GET \
  --authorization-type NONE \
  --no-api-key-required \
  --request-parameters {}
```

作成に成功すると以下のような json が返ります。

```json
{
    "httpMethod": "GET",
    "authorizationType": "NONE",
    "apiKeyRequired": false,
    "requestParameters": {}
}
```

## API Gateway から Lambda への統合リクエストを定義する
2つ目は、API Gateway　から Lambda 関数へのリクエストを定義しますが、まずは、Lambda 関数の ARN を確認します。

### Lambda 関数のARN を確認する

Lambda 関数の情報を取得する ```lambda get-function``` コマンドで ARN を確認することができます。

```sh
aws lambda get-function --function-name adventcalendar2021
```

取得できると、以下のような json が返るので、FunctionArn の値を確認します。

```json
{
    "Configuration": {
        "FunctionName": "adventcalendar2021",
        "FunctionArn": "arn:aws:lambda:ap-northeast-1:************:function:adventcalendar2021",
        "Runtime": "python3.8",
(以下、省略)
```

### API Gateway から Lambda へのリクエストを定義する
FunctionArn の値が確認できたら、```apigateway put-integration``` コマンドで API Gateway から Lambda 関数へのリクエストを定義します。

```uri``` に指定する形式は、```arn:aws:apigateway:<リージョン>:lambda:path/2015-03-31/functions/<Lambdaの関数のARN>/invocations``` です。

```sh
aws apigateway put-integration \
  --rest-api-id <API の ID> \
  --resource-id <"/" のID> \
  --http-method GET \
  --integration-http-method POST \
  --type AWS \
  --uri arn:aws:apigateway:ap-northeast-1:lambda:path/2015-03-31/functions/<Lambdaの関数のARN>/invocations
```

コマンド実行が正常に完了すると、以下のような json が返ります。
```uri``` の後程使用しますので、確認しておきます。

```json
{
    "type": "AWS",
    "httpMethod": "POST",
    "uri": "arn:aws:apigateway:ap-northeast-1:lambda:path/2015-03-31/functions/arn:aws:lambda:ap-northeast-1:************:function:adventcalendar2021/invocations",
    "passthroughBehavior": "WHEN_NO_MATCH",
    "timeoutInMillis": 29000,
    "cacheNamespace": "g8********",
    "cacheKeyParameters": []
}
```

## Lambda から API Gateway への統合レスポンスを定義する
Lambda 関数の処理結果(レスポンス)を API Gateway が受け付けるために ```apigateway put-integration-response``` コマンドで定義します。

```sh
aws apigateway put-integration-response \
      --rest-api-id <API の ID> \
      --resource-id <リソース の ID> \
      --http-method GET \
      --status-code 200 \
      --response-templates '{"text/html": ""}'
```

問題がなければ、以下のような json が返ってきます。

```json
{
    "statusCode": "200",
    "responseTemplates": {
        "text/html": null
    }
}
```

## API Gateway からクライアントへのメソッドレスポンスを定義する
最後の定義です。API Gateway からクライアントへのレスポンスを ```apigateway put-method-response``` コマンドで定義します。

```sh
aws apigateway put-method-response \
      --rest-api-id <API の ID> \
      --resource-id <リソース の ID> \
      --http-method GET \
      --status-code 200 \
      --response-models '{"text/html": "Empty"}'
```

こちらも問題がなければ、以下のような json が返ってきます。

```json
{
    "statusCode": "200",
    "responseModels": {
        "text/html": "Empty"
    }
}
```

これで一連の要素の作成、定義ができました。

## Lambda が API Gateway からのリクエストを受けられるように設定する
Lambda 関数が API Gateway からのリクエストを受け付けられるようにパーミッションを追加します。
```lambda add-permission``` コマンドを実行します。

```sh
aws lambda add-permission --function-name adventcalendar2021 \
  --statement-id adventcalendar2021-lambda-permission \
  --action "lambda:InvokeFunction" \
  --principal  apigateway.amazonaws.com \
  --source-arn "arn:aws:execute-api:ap-northeast-1:<アカウントID>:<API ID>/*/GET/"
```

問題がなければ、以下のようなパーミッションが埋め込まれた json が返ります。

```json
{
    "Statement": "{\"Sid\":\"adventcalendar2021-lambda-permission\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"apigateway.amazonaws.com\"},\"Action\":\"lambda:InvokeFunction\",\"Resource\":\"arn:aws:lambda:ap-northeast-1:<アカウントID>:function:adventcalendar2021\",\"Condition\":{\"ArnLike\":{\"AWS:SourceArn\":\"arn:aws:execute-api:ap-northeast-1:<アカウントID>:<API ID>/*/GET/\"}}}"
}
```

## API をテストする
各要素の作成や定義、Lambda 関数のパーミッション設定が済んだら、テスト実行してみます。
```apigateway test-invoke-method``` コマンドを実行します。

```sh
aws apigateway test-invoke-method --rest-api-id <API の ID> \
  --resource-id <リソースの ID> \
  --http-method GET \
  --path-with-query-string ''
```

テストの実行が終わると以下のような json が返ります。
```status: 200``` が出ていれば特に問題ありません。
また、```body``` の内容が今回であれば、 Lambda 関数が出力する HTML の内容になっていることを確認します。

```json
{
    "status": 200,
    "body": ....
(以下、省略)
```

## API をデプロイする
テストも問題がなければ、API を実際に使える状態にするために ```apigateway create-deployment``` コマンドで API をデプロイします。

```sh
aws apigateway create-deployment \
      --rest-api-id <API の ID> \
      --stage-name PROD \
      --stage-description "Production" \
      --description "Advent Calendar2021 API"
```

正常にデプロイが完了すると、以下のような json が返ってきます。

```json
{
    "id": "ul****",
    "description": "Advent Calendar2021 API",
    "createdDate": "2021-12-23T16:34:18+00:00"
}
```

## 動作確認
API がデプロイできたので、実際に動作確認をします。
curl コマンドを使い、さらに見やすくするために適宜 ```sed``` コマンドで改行を入れていきます。

```sh
curl "https://<API の ID>.execute-api.ap-northeast-1.amazonaws.com/PROD/"| sed "s/br>/br>\n/g" | sed "s/<\/h2>/<\/h2>\n/g"
```

API から正常にレスポンスが返ると、以下のような出力されます。

```sh
"<HTML><TITLE>AWS Lambda Environment Information</TITLE><BODY><h1>AWS Lambda Environment Information</h1><h2>AWS Lambda Environmental Variables</h2>
AWS_LAMBDA_FUNCTION_VERSION=$LATEST<br>
(以下省略)
```

## まとめ
昨日作成した Lambda 関数が API Gateway 経由で利用可能になりました。
これでいつでも、 Lambda 自体の各種情報が取得できますね！

さて、明日は最終回。
24日分の内容を振り返りつつ、後片付けをしましょう。