【AWS】IAM-APIGetway-Lambda-DynamoDB-S3でシンプルなアプリケーション制作

# はじめに　
サーバーレス勉強する際に、いろいろ試したメモ、
つまずいた点や、解決法など、主に自分用のメモになります。
他の方の参考にもなれば嬉しいです。

# やること

- DynamoDBでテーブル作成
- IAMでDynamoDB用のロール作成
- Lambda上でDynamoDBに値を挿入
- Lambda上でDynamoDBから値を取得
- API Gatewayの設定
- S3にウェブアプリケーションをアップし、公開する
- 公開されたアプリケーションでDynamoDBを操作する

# DynamoDBでテーブル作成
`テーブルの作成` をクリックしてください。
![UNADJUSTEDNONRAW_thumb_42.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320164/e8b36328-a977-b97b-9a40-85a61a69fe36.jpeg)
`テーブル名`と`プライマリキー`を入力します、`プライマリキー`のタイプは`数値`を選んでください。
![2020-02-07 17.31のイメージ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320164/2e04d494-b7e1-09f9-71e8-64b91ea249e6.jpeg)

`デフォルト設定の使用`のチェックを外します、今回はテストのため、性能は最低限のもので良いです。
![2020-02-07 17.56のイメージ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320164/aeab83c5-4347-3b69-3e4a-a746601eab3e.jpeg)

設定が終わったら`作成`をクリックします、しばらくしたらテーブルが作成されるはずです。
![UNADJUSTEDNONRAW_thumb_45.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320164/438642b7-cc7e-a45d-2373-ddde24db1588.jpeg)

# IAMでDynamoDB用のロール作成
権限なしではLambdaがDynamoDB操作できません、Lambda作成する前にまずロールを作ります。
`AWSサービス`の`Lambda`を選び、`次のステップ`を押してください。

![2020-02-07 19.05のイメージ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320164/617c4a1d-9f2f-7e66-3e0f-622d47a542df.jpeg)
Dynamoを検索して、`AmazonDynamoDBFullAccess`と`AWSLambdaDynamoDBExecutionRole`にチェック入れてください。
![2020-02-07 19.09のイメージ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320164/c0a24d68-a044-ef7c-3bb1-8dc623fcabc0.jpeg)
タグの追加に関しては、わかりやすいkeyとvalueでいいと思います。
![2020-02-07 19.16のイメージ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320164/dfb2bef4-b468-60c4-a1c1-126a6d371c28.jpeg)
ロール名も用途が分かりやすいもので良いです、作成完了したら、Lambdaの方に入ります。
![2020-02-07 19.19のイメージ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320164/0ebb3ea7-73cd-5f39-ad56-21c168c808fd.jpeg)

# Lambda上でDynamoDBに値を挿入
関数を作ります。
`関数の作成`をクリック。
`一から作成`を選択、関数名は用途が分かりやすいものにします。
言語は今回`Node.js`にします。
`アクセス権限`は先ほど作って置いたロールを使用します。
設定が終わったら、関数を作成します。
![2020-02-07 20.07のイメージ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320164/2524343b-d2ab-3144-f5b5-82c743bce8a2.jpeg)

関数の内容はリクエストから`message`を受け取って、DynamonDBに保存するというシンプルな内容でした。

```javascript:index.js

"use strict"
console.log("loading function");
var AWS = require("aws-sdk");
AWS.config.region = "ap-northeast-1";

var docClient = new AWS.DynamoDB.DocumentClient();

exports.handler = function(event, context, callback)  {
  var params = {
      Item:{
          data: Date.now(),
          message: event.message
      },
      TableName: "Lambda-DynamoDB-Write-Read",
  };
  docClient.scan(params, function(err, data){
      if(err){
          console.log("Fail to write into DynamoDB");
          callback(err, null);
      }else{
          console.log("Successfully write into AWS DynamoDB");
          callback(null, data);
      }
  });
};
```
# Lambda上でDynamoDBから値を取得
設定は値挿入時と同じです。
今回はデータの読み取りなので、関数名は`Lambda-DynamoDB-read-test`にします。

```javascript:index.js
"use strict"
console.log("loading function");
const AWS = require("aws-sdk");
AWS.config.region = "ap-northeast-1"
var docClient = new AWS.DynamoDB.DocumentClient();

exports.handler = function(event, context, callback){
    var params = {
        TableName: "Lambda-DynamoDB-Write-Read",
        Limit: 100
    };
    docClient.scan(params, function(err, data){
        if(err){
            console.log("Fail to read from AWS DynamoDB");
            callback(err, null);
        }else{
            console.log("Successfully Read from AWS DynamoDB table");
            Reflect.set(data, "headers", {
                "Access-Control-Allow-Origin" : "*",
                "Access-Control-Allow-Credentials": "true"}
                );
            Reflect.set(data, "responseCode", 200);
            context.succeed(data);
        }
    });
}
```
# API Gatewayの設定
APIを作成します。
`REST API`を選択します。
![2020-02-07 21.45のイメージ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320164/bc0a6982-966f-cf5c-c3db-cdd06a8dba62.jpeg)
API名と説明を入力して、作成します。![2020-02-07 22.21のイメージ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320164/e363ce32-0ecb-2def-7359-0873692464ec.jpeg)
作成完了後、メニューの`アクション`から、`メソッドの作成`を選択して、`GET`と`POST`を作ります。
![2020-02-07 22.29のイメージ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320164/0d75eace-1672-7481-7534-a23d7650d826.jpeg)
## GET
`Lambda関数`にチェックを入れて、
Lambda関数の所に先程作った、DynamoDBから値を取得用のLambda関数名を入れます。
![2020-02-07 22.31のイメージ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320164/ff15c775-f6d1-3fa0-8020-38f7b6adb465.jpeg)
`Lambda 関数に権限を追加する`のダイアログが出てきますが、`ok`を選択します。
`CORS`を有効化します、`アクション`から`CORS の有効化`にしてください。
![2020-02-08 11.45のイメージ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320164/3c09c0fc-ab2d-9eab-c016-7701a5d2aa4c.jpeg)
`アクション`から、`APIのデプロイ`を行ないます。
![2020-02-08 11.47のイメージ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320164/175c58d1-3b6e-ba59-e6e2-b4bdd099283e.jpeg)
`新しいステージ`を選択して、
`ステージ名*`、`ステージの説明`、`デプロイメントの説明`を入力します。
![2020-02-08 16.28のイメージ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320164/ff52c54c-bd23-e4ec-3a4c-b878a4c4fd7e.jpeg)
デプロイ完成したら、スタージでメソッド確認できます。
![2020-02-08 16.45のイメージ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320164/31b29114-a4a0-102a-0c1b-98409dabe1bb.jpeg)

## POST
手順はGET時と基本同じです。
先程作った値を挿入用のLambda関数を使用します。
![2020-02-08 17.08のイメージ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320164/ccd718e1-b462-3d6d-cbdc-2973770dba79.jpeg)
作った後、`統合リクエスト`を選択します。
<img width="574" alt="123.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320164/1117ff57-671f-2e0a-5ed7-2e6c8e47455f.jpeg">

`マッピングテンプレート`に`application/json`を`Content-Type`に追加します。
![2020-02-08 17.21のイメージ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320164/2f677c20-9248-71bf-2ff3-09c9ecf42021.jpeg)
デプロイする際に、先程作ったステージを選択します。
![2020-02-08 17.36のイメージ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320164/3c61c5a8-0e78-613c-bd73-f17252c6643f.jpeg)
完了後のステージはこんな感じになります。
![2020-02-08 17.45のイメージ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320164/df72c819-4665-e652-95d1-65e5d3831769.jpeg)

# S3にウェブアプリケーションをアップし、公開する
使用するウェブアプリのソースは以下になります。
Jqueryのmin.jsを同じディレクトリに置いてあります。
機能はajax使用して、ApiGatewayにGETとPOSTのリクエストを送り、
DynamoDBにデータ挿入、また取得します。

```html:LamdbaAPIGetwanyDynamoDB.html 
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title1</title>
    <script type="text/javascript" src="./jquery-2.1.4.min.js"></script>
</head>
<body>
<div id="entries">

</div>
<h1>Write new comment</h1>
<form>
    <label for="message">Message</label>
    <textarea id="message"></textarea>
    <button id="submitbutton">submit</button>
</form>
<script type="text/javascript">
    var API_Gateway_URL = "APIのURL";
    $(document).ready(()=>{
        $.ajax({
            type: "GET",
            url: API_Gateway_URL,
            success: (data)=>{
                $("#entries").html("");
                data.Items.forEach((getcomments)=>{
                    $("#entries").append("<p>" + getcomments.message+ "</p>");
                })
            }
        });
    });
    $(function () {
          $("#submitbutton").click(() => {
              console.log($("#message").val());
        $.ajax({
            url: API_Gateway_URL,
            type: "POST",
            data: JSON.stringify({"message": $("#message").val()}),
            contentType:'application/json',
            success: function (data) {
                location.reload();
            }
        });
        return false;
    })
    })
</script>
</body>
</html>
```
## S3のパケット作ります
`パケット名`を入力し、リージョンは東京を使用します。
`作成`でパケットを作ります。
![2020-02-08 18.24のイメージ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320164/14525a3d-9b92-88b7-233a-f84a18349edc.jpeg)
`フォルダ`を作ります。
![2020-02-08 18.36のイメージ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320164/b30ef645-1c0d-bf28-31d2-237bfdfe203f.jpeg)
ウェブアプリのファイルとjqueryのmin.jsを同じフォルダーにアップロードします。
![2020-02-08 18.39のイメージ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320164/6cd13835-79c7-db9b-43e1-9c4cd12de087.jpeg)
アップロードされたファイル(HtmlをJqueryのmin.js)にチェック入れて、
`アクション`から公開します。
![2020-02-08 18.58のイメージ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320164/e738a4b3-712a-2df4-103b-bd7125fd7fad.jpeg)

# 公開されたアプリケーションでDynamoDBを操作する
公開されたHtmlファイルのurlを開いて、実際操作します。
![35cca2645658fe236fc58df751594306.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320164/d8d84a84-3de7-2272-b45c-4f6a16b3e3c1.gif)
以上で終わりです。:relaxed:

# 追記
## kinsisでLambdaを呼び出す(追加中)
### 手順
- 実行ロールのアクセス権限
- Kinesisnのstreamを作成
- lambda関数の作成
- awscli使ってテスト 

### 実行ロールのアクセス権限
コマンドラインからkinesisnにデータを送り、そしてLambdaを呼び出して、
そのデータをDynamoDBに保存するという仕組みを作ります。
以下の権限を既存ロール`Lambda-DynamoDB-Write-Read`に追加
 - kinesis:DescribeStream
 - kinesis:DescribeStreamSummary
 - kinesis:GetRecords
 - kinesis:GetShardIterator
 - kinesis:ListShards
 - kinesis:ListStreams
 - kinesis:SubscribeToShard
 [参照元](https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/with-kinesis.html#events-kinesis-permissions)

### Kinesisnのstreamを作成
名前を入力して、シャード数は1で十分使えます。
![2020-02-14 15.41のイメージ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320164/13f57384-e671-d98d-b2a7-39301c6e762b.jpeg)

### lambda関数の作成
作成する際に、ロールも追加します。

```javascript:index.js

"use strict";
console.log("loading function");
var AWS = require("aws-sdk");
var docClient = new AWS.DynamoDB.DocumentClient();
AWS.config.region = 'ap-northeast-1';

exports.handler = (event, context, callback) => {
   
   event.Records.forEach((record)=>{
      
      var payload = Buffer.from(record.kinesis.data,"base64").toString("ascii");
      console.log("Decoded payload", payload);
      var params = {
       Item: {
           data : Date.now(),
           message: payload,
       },
      TableName: "Lambda-DynamoDB-Write-Read"
      };
      docClient.put(params, (err, data)=>{
       if(err){
           callback(err, null);
       }else{
           callback(null, data);
       }
   });
   });
};
```
トリガーを追加
![2020-02-14 15.46のイメージ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320164/1574aa8c-23e1-e5e5-ab65-b59e4483f415.jpeg)

### awscli使ってテスト
```shell
aws kinesis put-record \
--stream-name [先程作ったkinesis-stream] \
--data "何か" \
--partition-key shardId-000000000000 \
--region ap-northeast-1
--profile [アカウトprofile]
```