DynamoDBが関連する機能の検証用にサンプル構成を作成するCDKを書いてみた

DynamoDBのドキュメントにあるサンプルテーブル構成を作成するCDK Stackを作成してみました。 DynamoDBが関連する機能を検証するときに便利かもしれません。
2023.12.07

DynamoDBのドキュメントにあるサンプルテーブル構成とは、これのことです。

書いてみた

ファイル構成は以下のとおりです。

stacks/prerequisite.ts

このあとで新機能のOpenSearch統合を検証するので、各テーブルにpointInTimeRecoverystreamが付いています。不要であれば外してください。

テーブルを作成したあと、aws-cdk-lib/triggersを使って、ドキュメントにある通りの初期データを投入しています。 aws-cdk-lib/triggersはCDKのデプロイ中にLambdaを実行する機能で、今回のようにDynamoDBの初期データ投入などで使えます。

import { Construct } from "constructs";
import * as cdk from "aws-cdk-lib";
import * as dynamodb from "aws-cdk-lib/aws-dynamodb";
import * as lambda from "aws-cdk-lib/aws-lambda";
import { NodejsFunction, OutputFormat } from "aws-cdk-lib/aws-lambda-nodejs";
import * as trigger from "aws-cdk-lib/triggers";

export class PrerequisiteStack extends cdk.Stack {
  public readonly productCatalogTable: dynamodb.ITable;
  public readonly forumTable: dynamodb.ITable;
  public readonly threadTable: dynamodb.ITable;
  public readonly replyTable: dynamodb.ITable;

  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    /**
     * //////////////
     * DynamoDB
     * @see https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/AppendixSampleTables.html
     */

    const productCatalog = new dynamodb.Table(this, "ProductCatalog", {
      tableName: "ProductCatalog",
      partitionKey: { name: "Id", type: dynamodb.AttributeType.NUMBER },
      pointInTimeRecovery: true,
      stream: dynamodb.StreamViewType.NEW_AND_OLD_IMAGES,
      billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,
      removalPolicy: cdk.RemovalPolicy.DESTROY,
    });

    const forum = new dynamodb.Table(this, "Forum", {
      tableName: "Forum",
      partitionKey: { name: "Name", type: dynamodb.AttributeType.STRING },
      pointInTimeRecovery: true,
      stream: dynamodb.StreamViewType.NEW_AND_OLD_IMAGES,
      billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,
      removalPolicy: cdk.RemovalPolicy.DESTROY,
    });

    const thread = new dynamodb.Table(this, "Thread", {
      tableName: "Thread",
      partitionKey: { name: "ForumName", type: dynamodb.AttributeType.STRING },
      sortKey: { name: "Subject", type: dynamodb.AttributeType.STRING },
      pointInTimeRecovery: true,
      stream: dynamodb.StreamViewType.NEW_AND_OLD_IMAGES,
      billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,
      removalPolicy: cdk.RemovalPolicy.DESTROY,
    });

    const reply = new dynamodb.Table(this, "Reply", {
      tableName: "Reply",
      partitionKey: { name: "Id", type: dynamodb.AttributeType.STRING },
      sortKey: { name: "ReplyDateTime", type: dynamodb.AttributeType.STRING },
      pointInTimeRecovery: true,
      stream: dynamodb.StreamViewType.NEW_AND_OLD_IMAGES,
      billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,
      removalPolicy: cdk.RemovalPolicy.DESTROY,
    });
    reply.addGlobalSecondaryIndex({
      indexName: "PostedBy-Message-Index",
      partitionKey: { name: "PostedBy", type: dynamodb.AttributeType.STRING },
      sortKey: { name: "Message", type: dynamodb.AttributeType.STRING },
    });

    /**
     * //////////////
     * Fixtures
     * @see https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/AppendixSampleTables.html
     */

    const triggerHandler = new NodejsFunction(this, "TriggerHandler", {
      runtime: lambda.Runtime.NODEJS_20_X,
      architecture: lambda.Architecture.ARM_64,
      bundling: {
        target: "node20",
        format: OutputFormat.ESM,
      },
    });
    productCatalog.grantWriteData(triggerHandler);
    forum.grantWriteData(triggerHandler);
    thread.grantWriteData(triggerHandler);
    reply.grantWriteData(triggerHandler);
    new trigger.Trigger(this, "Trigger", {
      handler: triggerHandler,
      executeAfter: [productCatalog, forum, thread, reply],
    });

    this.forumTable = forum;
    this.productCatalogTable = productCatalog;
    this.threadTable = thread;
    this.replyTable = reply;
  }
}

stacks/prerequisite.TriggerHandler.ts

ドキュメントとの整合性のため、@aws-sdk/lib-dynamodbではなく@aws-sdk/client-dynamodbを使っています。 アプリケーションを書くときは@aws-sdk/lib-dynamodbで楽しましょう!

import { DynamoDB } from "@aws-sdk/client-dynamodb";

const dynamodb = new DynamoDB({ region: "ap-northeast-1" });

export const handler = async () => {
  await dynamodb.batchWriteItem({
    RequestItems: {
      // 長いので割愛します。
      // こちらを御覧ください。
      // https://github.com/yamatatsu/play-zero-ETL-to-OpenSearch-from-DDB/blob/main/src/stacks/prerequisite.TriggerHandler.ts
    },
  });
};

リポジトリ

ここに置きました。

まとめ

便利かもしれない!