AWS+NodeJSでサーバレスな環境構築③

# はじめに
[前回の記事](https://qiita.com/isacRU/items/f5a16683331779805a1b)ではDynamoDBのテーブルと項目作成、Lambda関数で使うロールやインラインポリシーの設定を行いました。今回はその続きで、API Gateway(REST APIでCRUD実装)をトリガーにし、Lambda(NodeJS)関数呼び出して、DynamoDBに参照や更新をできるようにします。
表現等が不適切の場合はご指摘いただければ、幸いです。
※サーバレスに関してよくわからない方は、[こちら](https://qiita.com/isacRU/items/fe4751603d3da32b2daf)をご覧いただければと思います。

# アーキテクチャ図
![serverless.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43096/d77beb25-d5cd-0908-9502-7645b2c76bdb.png)


# 流れ
- ソースで直接(Api gatewayを使わず)参照や更新ができるかを確認
- POST(ユーザーの登録)
  - domain.com/users/{id}
- DELETE(対象ユーザーの削除)
  - domain.com/users/{id}
- GET(全ユーザーの取得)
  - domain.com/users
- PATCH(対象ユーザーの更新)
  - domain.com/users/{id}

# ソースで直接(Api gatewayを使わず)参照や更新ができるかを確認
まずはLambda(NodeJS)でDynamoDBテーブルが参照・更新できるか確認
Lambdaダッシュボード＞関数の作成＞一から作成＞以下の通り入力＞関数の作成ボタン
※既存のロール設定は[前回の記事](https://qiita.com/isacRU/items/f5a16683331779805a1b)で作成したものを使用しています。
<img width="1294" alt="スクリーンショット 2020-01-03 19.43.16.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43096/4dce4ddc-c96c-414a-b733-a5274012ce80.png">


データの参照ができるよう、ソース編集
[こちら](https://docs.aws.amazon.com/ja_jp/sdk-for-javascript/v2/developer-guide/dynamodb-example-table-read-write.html)のリファレンスを参考にしました。

```javascript:index.js
'use strict';

const AWS = require('aws-sdk');
const myRegion = "us-east-2";

AWS.config.update({ region: myRegion});

exports.handler = async (event, context) => {
  const documentClient = new AWS.DynamoDB.DocumentClient({ region: myRegion});

  //読込用のデータ
  const params1 = {
    TableName: "Users",
    Key: {
      id: "01"
    }
  };
  //書込用のデータ
  const params2 = {
    TableName: "Users",
    Item: {
      id: "02",
      firstname: "first02",
      lastname: "last02"
    }
  };

  try {
    const readData = await documentClient.get(params1).promise();
    const writeData = await documentClient.put(params2).promise();
    console.log(readData);
    console.log(writeData);
  } catch (err) {
    console.log(err);
  }
};
```
⚠️ 必ず、DynamoDBとLambdaは同じリージョンで作成するように気をつける。また上記ソースのmyRegion変数値も合わせるように気をつける。いずれが満たない場合、AccessDeniedExceptionという~~意味不明な~~エラーが発生する可能性があります。

テストイベントの設定＞テストボタン＞取得結果が表示されれば、OK
<img width="1294" alt="スクリーンショット 2020-01-03 19.58.10.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43096/4d83f87f-244e-a3d1-efa0-9f22bf20d7b5.png">

DynamoDBにデータ作成されていることを確認
ちなみに、params2でidをそのまま、firstnameやlastnameを変更すると更新される仕様です。
<img width="933" alt="スクリーンショット 2020-01-03 20.00.54.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43096/19506db5-139a-7a40-c844-c99dde716763.png">

# API Gatewayトリガー追加と設定
API Gatewayダッシュボード＞APIを作成ボタン＞REST APIの構築ボタン(Privateじゃない方)
以下のように入力＞APIの作成ボタン
<img width="1229" alt="スクリーンショット 2020-01-03 20.32.20.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43096/501628b9-63d3-b37a-88b3-130e5b130ee4.png">

エッジ最適化について(AWS公式より引用)
>エッジ最適化 API は、API ゲートウェイによって作成および管理される CloudFront ディストリビューション経由でアクセスするエンドポイントです。以前は、エッジ最適化 API は、API ゲートウェイを使用して API を作成する際のデフォルトオプションでした。

**参考記事**
・[0からREST APIについて調べてみた](https://qiita.com/masato44gm/items/dffb8281536ad321fb08)
・[エッジ最適化について説明](https://aws.amazon.com/jp/about-aws/whats-new/2017/11/amazon-api-gateway-supports-regional-api-endpoints/)

# リクエスト、レスポンスマッピングのモデルを作成及び設定
[参考](https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/models-mappings.html#models-mappings-tasks)
モデル名、コンテンツタイプ、スキーマ(ソース)を設定します。
<img width="1439" alt="スクリーンショット 2020-01-03 21.41.42.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43096/b2ca5f84-e2e1-84cd-a5bf-410063b897c0.png">

```json:スキーマのソース
{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "title": "UsersInputModel",
  "type": "object",
  "properties": {
      "id": {"type": "string"},
      "firstname": {"type": "string"},
      "lastname": {"type": "string"}
  }
}
```

アクション＞リソースの作成
リソースは２つ作成します。
<img width="963" alt="スクリーンショット 2020-01-03 21.13.48.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43096/5943a623-2afd-2787-dd0e-b32852c87e9d.png">
<img width="968" alt="スクリーンショット 2020-01-03 21.15.55.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43096/d70c6233-dba8-a685-ac88-da19c1c711cf.png">


# POSTメソッド実装(ユーザーの登録)
ここではAPI GatewayでPOSTメソッドを作成して、レコードが登録されるかを確認する。
### API Gatewayと紐付けるLambda関数を作成と設定
関数名はputUsersで、その他の設定は前回と一緒~~(察して)~~(冒頭のLambda関数作成のスクリーンショット参照)

以下のソースを貼り付けます。
DynamoDBの構成に関しては、こちらの記事を参考にしてください。(DynamoDBテーブルの作成部分)

```javascript:index.js
'use strict';
const AWS = require('aws-sdk');
const myRegion = "us-east-2";

AWS.config.update({ region: myRegion});

exports.handler = async (event, context) => {
  const documentClient = new AWS.DynamoDB.DocumentClient({ region: myRegion});

  let responseBody = "";
  let statusCode = 0;

  const { id, firstname, lastname } = JSON.parse(event.body);

  const params = {
    TableName: "Users",
    Item: {
      id: id,
      firstname: firstname,
      lastname: lastname
    }
  };

  try {
    const data = await documentClient.put(params).promise();
    responseBody = JSON.stringify(data);
    statusCode = 201;
  } catch (err) {
    responseBody = `Unable to put user ${err}`;
    statusCode = 403;
  }

  const response = {
    statusCode: statusCode,
    headers: {
       "Content-Type": "application/json"
    },
    body: responseBody
  };

  return response;
}
```

### POSTメソッド作成と設定
アクション＞メソッドの作成
<img width="970" alt="スクリーンショット 2020-01-03 21.24.17.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43096/ce297b44-a485-46b4-3ada-55940d40836b.png">

メソッドリクエストの設定
モデルの追加には上記の作成したモデルを追加する
<img width="979" alt="スクリーンショット 2020-01-03 21.46.26.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43096/e7f66cd3-e288-6e8c-3da9-b9c2e7786f27.png">

### API Gatewayで確認テスト
下の方にテストボタンあるので、それを押すとテスト結果(ログも含めて)画面右側に表示されると思います。
<img width="1176" alt="スクリーンショット 2020-01-03 22.12.05.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43096/f17956ab-e49a-7074-bf7e-11111930a1bf.png">

<img width="755" alt="スクリーンショット 2020-01-03 22.23.42.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43096/5ebeddc8-a06e-2bfb-5a78-dd8a1d258ff4.png">

```json:リクエスト本文
{
    "id": "03",
    "firstname": "first03",
    "lastname": "last03"
}
```
テストステータスで２０１が返ってこれば、成功みたいです。
⚠️ ちなみに本来DynamoDBテーブルにない項目論理名(例えばfirstnameではなく、あえてnickname)をリクエスト本文に設定された場合、問題なくテスト処理は実行されます。対象のレコードfirstnameには空白が入る仕様になっています。

DynamoDBテーブルにレコードが作成されていることを確認
<img width="925" alt="スクリーンショット 2020-01-03 22.27.09.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43096/347b80d6-5474-7670-4de4-deca138f80c4.png">

# to be continued
ちょっと長くなりそうなので、続きを次回出します。
あとはDELETE(対象ユーザーの削除), GET(全ユーザーの取得) PATCH(対象ユーザーの更新)のメソッドを作成して、最後までCRUD機能を実装していきます。