【AWS API Gateway】Lambda関数（DynamoDB内データ取得関数）実行API作成

##目標
API Gatewayを利用して、Lambda関数（DynamoDB内データを取得する関数、Rubyでの作成とする。）実行API（※）を作成する。
※作成するAPIの詳細要件
・URLのクエリパラメータとしてDynamoDBのプライマリキー情報を指定し、取得するデータを絞り込む。
・クエリパラメータが指定されていない場合、ステータスコード400エラーを返す。
・DynamoDBからクエリパラメータに紐づくデータを取得出来ない場合も同様に、ステータスコード400エラーを返す。
##API Gatewayとは
API Gatewayを利用することでバックエンドリソースのLamda関数、その他AWSサービス、httpエンドポイントに対するRestfulAPI（※１）やWebSocketAPI（※２）を作成することが可能となります。
API Gatewayに関するより詳細な知識を掲載している記事のリンク記載致します。
[Amazon API Gateway](https://qiita.com/leomaro7/items/66ea3233097fa410fef9)
※１
URLには処理対象のリソースを指定するだけで、どのような処理を行うかは（URL文字列でなく）httpのメソッドに一任することを可能としているAPIのこと
※２
WEBの双方向通信用プロトコル、通常のクライアント起点⇒サーバ通信だけでなく、サーバ起点⇒クライアント通信も可能とする。リアルタイムチェットアプリケーション等で利用

##構成図
![apigateway (5).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647616/9669a4c8-648d-e5e7-61c2-aad58cad9457.png)
①**メソッドリクエスト**
クライアントからAPIゲートウェイによって作成されたAPIを利用してhttpsアクセスします。
ここでクエリパラメータとしてDynamoDBのプライマリキー情報指定を必須とするよう設定を行います。
②**統合リクエスト**
**アップストリーム**（API Gatewayのバックエンド）であるLambda関数へリクエストを投げます。
ここで**Lambdaプロキシ統合**という機能を利用して、LambdaにURLクエリパラメータを渡す設定を行います。
③DynamoDBアクセス
Lambda関数を実行し、その関数内処理からDynamoDBへアクセスします（AWS SDK For Ruby利用）。
④DynamoDBデータ取得
DynamoDBからクエリパラメータに指定した情報に紐づくデータを取得します。
⑤**統合レスポンス**
Lambda関数の実行結果がAPI Gatewayへレスポンスされます。
（今回はLambdaプロキシ統合を利用しているためステータスコードのマッピング設定等不要）
⑥**メソッドレスポンス**
API Gatewayからクライアントへレスポンスを返します。
##作業の流れ
| 項番 | タイトル |
|:----:|:-------------|
| 1 | [DynamoDBテーブルの作成](#1dynamodbテーブルの作成) |
| 2 | [Lambda関数の作成](#2lambda関数の作成)|
| 3 | [APIの作成](#3apiの作成)|
| 4 | [動作検証](#4動作検証)|
##手順
###1.DynamoDBテーブルの作成
本記事では大まかな流れだけの説明と致します（※）。
テーブル名は`test-table`、プライマリキーは`id`（数値型）で作成
※Dynamoの基本的な構築手順は以下で記載
[【AWS DynamoDB】基本構築](https://qiita.com/aWdfcfG2jLr73pe/items/35f902f4c0992f532705)
![tempsnip.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647616/59dbc828-5e5f-a396-82f8-010ad343f1ff.png)
作成したテーブルに以下のように、name属性をアペンドした項目をテストデータとして追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647616/0657b83a-8fab-bfd4-5a13-894c585346d0.png)
###2.Lambda関数の作成
本記事では大まかな流れだけの説明と致します。
関数名は`dynamodb-get`で開発言語は`Ruby.2.7`として作成
※以前実施したLambda関数の基本構築は以下記事
[【AWS Lambda】S3に保存された画像をリサイズして別S3に保存(Ruby利用)](https://qiita.com/aWdfcfG2jLr73pe/items/7214a3611baa8ab13759)
![tempsnip.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647616/388e1867-03b5-3806-112d-a4488e02fea9.png)
以下のコードをLambda関数のコードとして利用します。

```ruby:lambda_function.rb
require 'aws-sdk'
def lambda_handler(event:, context:)
 dynamoDB = Aws::DynamoDB::Resource.new(region: 'ap-northeast-1')
 table = dynamoDB.table('test-table')
 # クエリパラメータで指定されたidに紐づくデータを取得する
 resp = table.get_item({
 key: { 'id' => event["queryStringParameters"]["id"].to_i }
 })
 # 取得結果に応じたレスポンス返す。
 if resp["item"]
 {
 'statusCode': 200,
 'body': resp.item['name']
 }
 else
 {
 'statusCode': 400,
 'body': JSON.generate({message: "The user with the specified id(#{event["queryStringParameters"]["id"]}) cannot be found!"})
 }
 end
end
```
Lambda関数からDynamoDBへアクセスをかけるため、`AmazonDynamoDBFullAccess`のAWS管理ポリシーをLambdaの実行ロールにアタッチします。
![tempsnip.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647616/ba9b8cc6-b788-b4b5-5653-c7420cf1d6dc.png)
###3.APIの作成
**①API作成開始**
「サービス」⇒「API Gateway」から`APIの作成`をクリック
![tempsnip.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647616/6e444a3c-4a40-084f-5c42-7d33bf2fe753.png)
**②APIタイプの選択**
今回はREST APIでのAPI作成とします。
`REST API`欄の`構築`をクリック
![tempsnip.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647616/4e915c74-7e1d-1971-345c-7bf5763a0d8d.png)
**③APIの詳細設定**
以下のように各項目（※）を選択します。
※**エンドポイントタイプ**について（AWSドキュメント抜粋）
**リージョン**：現在設定しているリージョンにAPIのエンドポイントが割り当てられます。
**エッジ最適化**：地理的に分散されたクライアントに最適です。APIリクエストは、最寄りの CloudFrontネットワークにルーティングされます。
**プライベート**：VPCからしかアクセスできない API エンドポイントです。
![tempsnip.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647616/34d0ed42-5570-5bc2-c55e-88ab68785f98.png)
**③メソッドの作成**
アクションのプルダウンメニューから`メソッドの作成`をクリック
![tempsnip.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647616/4dacbe56-a538-42bb-d9bf-cc636415ffb6.png)
`GET`メソッドを選択した後、チェックマークをクリック
![tempsnip.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647616/fee34349-557d-a4a9-9bf1-1dc99abd620b.png)
次に、API Gatewayがどのリソースと統合（連携）を行うかという設定を行います。
今回はLambda関数と統合し、かつ`Lambdaプロキシ統合の使用`（※１）を行います。
Lambda関数欄には先ほど作成したLambda関数`dynamodb-get`を記載
※１**Lambdaプロキシの統合**
API GatewayをLambda関数と統合させる場合、個人的にはこれを使った方が実装かなり楽でした。
Lambdaプロキシの統合を使用することで、API Gatewayから対象のLambda関数へevent（Lambda関数内で使用できるイベントソースから送られてくる情報）を自動フォーマット調整して送信することが可能となります。
また、Lambda関数からAPI Gatewayへのレスポンス内容は自動的にフォーマット調整され、統合レスポンスでのステータスコードマッピング調整等が不要となります。
以下記事でLambdaプロキシ統合に関する詳細が記載してあり、分かりやすかったです。
[API Gateway + Lambda プロキシ結合の使用有無による違い](https://qiita.com/yuuwatanabe/items/a3bd65e709f20574b6db)
![tempsnip.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647616/a9fca001-79b1-b75b-d28b-93a5f49aab7b.png)
API GatewayがLambda関数へアクセス出来るよう権限追加（※２）を行います。`OK`クリック
![tempsnip.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647616/8728d117-7102-f22c-0213-f2b5c340bdc8.png)
※２ちなみに、この後Lambda関数のトリガーにAPI Gatewayが自動設定されました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647616/025b0e72-f061-a6e7-a437-9ecb2eb45458.png)
**④リクエストの調整**
**メソッドリクエスト**を調整することで、URLにクエリパラメータを付加することを必須にします。
作成したAPIの`メソッドリクエスト`をクリック
![tempsnip.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647616/e0fda799-4b20-d708-e5d8-4994529993cf.png)
**※余談**
**Lambdaプロキシ統合**を利用すると、**統合リクエスト**、**統合レスポンス**、**メソッドレスポンス**に関しては自動でLambdaプロキシ仕様になり、基本的には調整が不要となることがリクエストレスポンス調整画面からわかります。
![tempsnip.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647616/cd04a4a6-d82d-7b46-b4bd-a68737948838.png)
リクエストの検証に`クエリ文字列パラメータおよびヘッダーの検証`を選択することで、クエリパラメータの検証を有効化（API Gatewayがクエリパラメータの内容をチェックするようになる）させます。
選択したらチェックをクリック
![tempsnip.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647616/39c3603b-080d-e7cd-cd96-eeef4f551932.png)
URLクエリ文字列パラメータ欄の名前に`id`（DynamoDBテーブルのプライマリキー）を入力してチェックをクリック
![tempsnip.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647616/3aeaffb6-5aba-3448-8a99-77af1ba14a5d.png)
更に`必須`にチェックを入れ、これをクエリパラメータに指定することを必須（もしクエリパラメータを指定しなかった場合エラーでアクセス拒否します）とします。
![tempsnip.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647616/4e85422f-3e0a-e83f-b522-65c96466b902.png)
**⑤デプロイ前検証**
APIのデプロイ前にテストを行います。
作成したAPIの詳細画面から`テスト`クリック
![tempsnip.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647616/aa691747-1a5a-88c1-a6b7-c0be67d8088e.png)
クエリ文字列欄に`id=1`を入力し、`テスト`をクリック
![tempsnip.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647616/de8b0d53-c222-cd0c-4217-211351d2f92e.png)
ステータスコードが200で、レスポンス本文に先ほど作成したDynamoDBテーブルのidが1である項目に紐づいたデータがレスポンスされればOKです。
![tempsnip.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647616/3763ae29-b6e1-3c99-0395-2f85bbf7ebc1.png)
**⑥APIのデプロイ**
作成したAPIを実際に外部から利用可能にするためデプロイを行います。
作成したAPIを選択した状態で、`アクション`⇒`APIのデプロイ`をクリック
![tempsnip.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647616/445a5e0c-0793-4fc3-aa67-e46858435bb4.png)
APIのデプロイを行うためには、**ステージ**を作成する必要があるため、`新しいステージ`をクリック
![tempsnip.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647616/57c198b2-7eb4-4fdb-0650-fabc79db4735.png)
ステージ名は`test`で`デプロイ`をクリック
![tempsnip.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647616/b3bca843-4892-edd8-6b92-9420a88cef5f.png)
URLの呼び出し欄にデプロイされたAPIが表示されます。
![tempsnip.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647616/5bbd3404-0f0c-e8d8-cd4f-e9045b12c3e3.png)
###4.動作検証
※テストデータとして使用するDynamoDBテーブルは以下の内容
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647616/0657b83a-8fab-bfd4-5a13-894c585346d0.png)
**①DynamoDBテーブルに存在するidをクエリパラメータとして指定（正常系）**
APIのデプロイ実行後にURLの呼び出し欄に記載されたURLに、クエリパラメータに`id=1`を指定してブラウザアクセスします。
以下のように、ステータスコード200（正常）かつ、DynamoDBテーブルのidが1である項目のnameが表示されます。
![tempsnip.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647616/dfe108bc-03e6-b721-5755-d83630cf2766.png)
**②クエリパラメータを指定しない（異常系1）**
クエリパラメータを指定せずブラウザアクセスをします。
ステータスコード400エラーで、必須クエリパラメータが指定されてないことを示すエラーメッセージが出ます。
![tempsnip.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647616/ef27193a-7f6a-3ab8-ab51-a99d4b12bc98.png)
**③DynamoDBテーブルに存在しないidをクエリパラメータとして指定（異常系2）**
クエリパラメータにDynamoDBに存在しない`id=5`を指定してブラウザアクセスします。
ステータスコード400エラーで、指定されたidに紐づくデータが存在しないことを示すメッセージが出ます
![tempsnip.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647616/b0be5b8b-23cd-0ecc-8fcf-b4bc677b703e.png)