API GatewayのLambdaプロキシ統合とは

# 概要
API Gateway作成時にあるLambdaプロキシ統合というものが気になったので、少しまとめてみました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3951176/b9ec08dc-3dd8-410c-bc2b-5a40c2f2ab8c.png)


# Lambdaプロキシ統合とは
ざっくりいうと、API Gatewayが受け取ったHTTPリクエスト全体を、evantパラメータとしてLambda関数に渡し、Lambda関数のレスポンスをそのままHTTPレスポンスとしてクライアントに返す統合方式です。
API Gatewayでは、レスポンスの形式を指定する方法として「マッピングテンプレート」がありますが、その設定も不要になっています。

https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html

# 実際に使ってみる
今回はデフォルトのLambda関数で試してみようと思います。また、APIGatewayも2種類作成して比較しました。
* プロキシ統合有効
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3951176/4f7ba75f-d5bb-489b-82ab-99ac49e648f7.png)

* プロキシ統合無効
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3951176/65461bcd-f327-4b8c-893e-89769ed30f0b.png)


```python
import json

def lambda_handler(event, context):
    # TODO implement
    return {
        'statusCode': 200,
        'body': json.dumps('Hello from Lambda!')
    }

```

Lambda統合プロキシの有無でそれぞれ以下のようにレスポンスが変化します。

Lambda統合プロキシがなしの場合
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3951176/60cce214-88e3-4106-9284-714d83a2323a.png)



Lambda統合プロキシありの場合

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3951176/4c8f42ef-5200-4bd7-9ded-6a25844a1c66.png)


これは冒頭で示した公式ドキュメントにあるように、body部の値をレスポンス部分として返してくれるようになっているからです。今回は'Hello from Lambda!'の部分がそのまま返ってきてくれたわけですね。

>
>```python
>{
>    "isBase64Encoded": true|false,
>    "statusCode": httpStatusCode,
>    "headers": { "headerName": "headerValue", ... },
>    "multiValueHeaders": { "headerName": ["headerValue", "headerValue2", ...], ... },
>    "body": "..."
>}
>```
>[プロキシ統合のための 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)
>


# 入力時の形式はあるのか
プロキシ統合を有効にすればあとはなんでもおっけ～というわけでもなく、Lambda入力時のお作法的なものも一応ありました。

>```
>{
>  "resource": "/my/path",
>  "path": "/my/path",
>  "httpMethod": "GET",
>  "headers": {
>    "header1": "value1",
>    "header2": "value1,value2"
>  },
>  "multiValueHeaders": {
>    "header1": [
>      "value1"
>    ],
>    "header2": [
>      "value1",
>      "value2"
>    ]
>  },
>  "queryStringParameters": {
>    "parameter1": "value1,value2",
>    "parameter2": "value"
>  },
>  "multiValueQueryStringParameters": {
>    "parameter1": [
>      "value1",
>      "value2"
>    ],
>    "parameter2": [
>      "value"
>    ]
>  },
>  "requestContext": {
>    "accountId": "123456789012",
>    "apiId": "id",
>    "authorizer": {
>      "claims": null,
>      "scopes": null
>    },
>   "domainName": "id.execute-api.us-east-1.amazonaws.com",
>    "domainPrefix": "id",
>    "extendedRequestId": "request-id",
>    "httpMethod": "GET",
>    "identity": {
>      "accessKey": null,
>      "accountId": null,
>      "caller": null,
>      "cognitoAuthenticationProvider": null,
>      "cognitoAuthenticationType": null,
>      "cognitoIdentityId": null,
>      "cognitoIdentityPoolId": null,
>      "principalOrgId": null,
>     "sourceIp": "IP",
>      "user": null,
>      "userAgent": "user-agent",
>      "userArn": null,
>      "clientCert": {
>        "clientCertPem": "CERT_CONTENT",
>        "subjectDN": "www.example.com",
>        "issuerDN": "Example issuer",
>        "serialNumber": "a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1",
>        "validity": {
>          "notBefore": "May 28 12:30:02 2019 GMT",
>          "notAfter": "Aug  5 09:36:04 2021 GMT"
>        }
>      }
>    },
>    "path": "/my/path",
>    "protocol": "HTTP/1.1",
>    "requestId": "id=",
>    "requestTime": "04/Mar/2020:19:15:17 +0000",
>    "requestTimeEpoch": 1583349317135,
>    "resourceId": null,
>   "resourcePath": "/my/path",
>    "stage": "$default"
>  },
>  "pathParameters": null,
>  "stageVariables": null,
>  "body": "Hello from Lambda!",
>  "isBase64Encoded": false
>}
>```
>[プロキシ統合のための 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)
>

ここで実際に値の受け渡しをしているのは"queryStringParameters"ですね。これ含めて、eventオブジェクトとしてLambdaにこれらのパラメータを渡しているようです。ではこれを踏まえて実際に試してみようと思います。

# queryStringParametersに値を渡してみる
以下のように'input_text'をeventオブジェクトとして受け取るように関数を変更します。
```python
import json

def lambda_handler(event, context):
    # TODO implement
    return {
        'statusCode': 200,
        'body': json.dumps(event['queryStringParameters']['input_text'])
    }
```
#### プロキシ統合有効時
* エンドポイント指定→?input_text=hello
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3951176/291339d0-b983-4094-bbf1-24ba16d7179f.png)

#### プロキシ統合無効時
* エンドポイント指定→?input_text=hello
```python
{
  "errorMessage": "'queryStringParameters'",
  "errorType": "KeyError",
  "requestId": "55f41ab8-9120-4ca4-8d25-608fd343bb5a",
  "stackTrace": [
    "  File \"/var/task/lambda_function.py\", line 7, in lambda_handler\n    'body': json.dumps(event['queryStringParameters']['input_text'])\n"
  ]
}
```
ここで言われているのは、'queryStringParameters'なんてキーないよと言われてしまっています。プロキシ統合を有効にすることでeventへのマッピングはすべてやってくれていたのですが、無効にしてしまうとやってくれないのでこのようなエラーが発生します。

## マッピングテンプレートを使用する
プロキシ統合を使用せずにレスポンスを取得するにはマッピングテンプレートを使用するのも一つの手です。
プロキシ統合使用時はeventオブジェクトとして構造化して使用していましたが、マッピングテンプレートにレスポンスの形を明示的に示すことで構造を作ることができます。

https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/models-mappings.html

今回は以下のように'input_text'を受け取れるようにしたいと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3951176/e38846de-927c-412c-93f5-6c6a1f0e72f2.png)

再デプロイ後同様にリクエストを送ったところ、queryStringParametersの値にマッピングテンプレートを使用してアクセスできました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3951176/001d0b53-caa9-4e27-81d9-e31cc7501624.png)

# まとめ
LambdaやAPI Gatewayは普段あまり触らないですが、学びなおすいい機会になりました。
最近全然ブログ書けてなかったのでもう少し頻度上げていきたい...