Serverless FrameworkでDynamoDBを使う

## テーブルの作成
テーブル名がusersTable、パーティションキー（ハッシュキー）がid(String型)、ソートキー（レンジキー）がname(String型)であるテーブルを作成します。

```ts:serverless.ts
const serverlessConfiguration: AWS = {
  provider: {
    region: "ap-northeast-1",
  },
  resources: {
    Resources: {
      // ResourceとしてDynamoDBを設定
      usersTable: {
        Type: "AWS::DynamoDB::Table",
        Properties: {
          TableName: "usersTable",
          // Primary KeyとSort Key(あれば)の型を指定
          AttributeDefinitions: [
            {
              AttributeName: "id",
              AttributeType: "S",
            },
            {
              AttributeName: "name",
              AttributeType: "S",
            },
          ],
          // # キーの種類を指定（ハッシュorレンジキー）
          // ハッシュ＝Primary Key, レンジキー=Sort Key
          KeySchema: [
            {
              KeyType: "HASH",
              AttributeName: "id",
            },
            {
              KeyType: "RANGE",
              AttributeName: "name",
            },
          ],
          // プロビジョニングするキャパシティーユニットの設定
          ProvisionedThroughput: {
            ReadCapacityUnits: 5,
            WriteCapacityUnits: 5,
          },
        },
      },
    },
  },
};
```
これで```sls deploy```してみると、```usersTable```というテーブルが作成される。

## Permissionの設定
>Every AWS Lambda function needs permission to interact with other AWS infrastructure resources within your account. These permissions are set via an AWS IAM Role. You can set permission policy statements within this role via the provider.iamRoleStatements property.
[Permissions](https://www.serverless.com/framework/docs/providers/aws/guide/functions/#permissions)

DynamoDBにアクセスするために```provider.iamRoleStatements``` を設定します。

```ts:serverless.ts
const serverlessConfiguration: AWS = {
  provider: {
    iamRoleStatements: [
      {
        Effect: "Allow",
        // 許可する処理を設定
        Action: ["dynamodb:PutItem", "dynamodb:GetItem"],
        // 処理を許可するリソースを設定
        Resource:
          "arn:aws:dynamodb:${opt:region, self:provider.region}:*:table/usersTable",
      },
    ],
  },
}
```

## Document Clientの設定
>DynamoDB ドキュメントクライアントは、属性値の概念を抽象化することによって項目の操作を簡素化します。
[DynamoDB ドキュメントクライアントの使用](https://docs.aws.amazon.com/ja_jp/sdk-for-javascript/v2/developer-guide/dynamodb-example-document-client.html)

Document Clientを使うと、DynamoDBインスタンスを使う時より、データ操作時の記述が簡易にできます。

```ts:handler.ts
// AWSの設定情報
const AWS = require("aws-sdk");

// 環境変数から秘匿情報を読み込み・設定
AWS.config.update({
  accessKeyId: process.env.accessKeyId,
  secretAccessKey: process.env.secretAccessKey,
  region: process.env.region,
});

// ハンドラ内でインスタンス作成
const documentClient = new AWS.DynamoDB.DocumentClient();
```

## データの作成
```ts:handler.ts
export const putData: APIGatewayProxyHandler = async (event, _context) => {
  const docClient = new AWS.DynamoDB.DocumentClient();

  const userInformation = {
    TableName: "usersTable",
    Item: {
      id: "1",
      name: 'sample tarou',
      emal: 'sample-tarou@sample.com',
      age: 30
    },
  };

  // await忘れるとデータの書き込みが終わる前にreturnされてしまう
  await docClient
    .put(userInformation)
    .promise()
    .catch((err) =>
      console.error(JSON.stringify(err))
    );

  return {
    statusCode: 200,
    body: JSON.stringify("Successfully data has been written."),
  };
};
```

## データの取得
```ts:handler.ts
export const getData: APIGatewayProxyHandler = async (event, _context) => {
  const documentClient = new AWS.DynamoDB.DocumentClient();

  const query_params = {
    TableName: "usersTable",
    KeyConditionExpression:
      "id = :generation_gender and #rank <= :limit",
    ExpressionAttributeValues: {
      ":id": "1",
    },
  };

  const data = await documentClient
    .query(query_params)
    .promise()
    .catch((err) => {
      console.error(JSON.stringify(err));
    });;
  // ここ.then()で繋いでしまうと戻り値としてデータが返ってこない(const data がnullになってしまう)ので注意
  
  return {
    statusCode: 200,
    body: JSON.stringify(data),
  };
};
```

他にも、DocumentClientには、複数データを一度にまとめて書き込み・読み込みできる```batchGet``` (100個まで)```batchWrite``` (25個まで)メソッドなどがある。

## 参考
Amazon DynamoDB and Serverless - The Ultimate Guide
https://www.serverless.com/dynamodb

Serverless FrameworkでAPIGateway・Lambda・DynamoDBを構築する
https://qiita.com/t_okkan/items/546330b5f4da720c71a7

DynamoDB ドキュメントクライアントの使用
https://docs.aws.amazon.com/ja_jp/sdk-for-javascript/v2/developer-guide/dynamodb-example-document-client.html

Class: AWS.DynamoDB.DocumentClient
https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/DynamoDB/DocumentClient.html#get-property