🍨

【SDK for JavaScript v3】TypeScriptでDynamoDBにCRUDする【SAM】

2024/03/15に公開

この記事の目的

  • AWS SAMを使ってAPI Gateway + Lambda + DynamoDBを作成する
  • TypeScriptを使ってDynamoDBを操作するコードの書き方が分かる(with AWS SDK for JavaScript

この記事で話さないこと

AWS SAMの環境構築(プロジェクトディレクトリはすでにあるものとする)

この記事で作成するリソース

AWS SAMでリソース定義(temlate.yamlを見る)

template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: |
  dynamo-test
Globals:
  Function:
    CodeUri: src/
    Runtime: nodejs20.x
    Timeout: 180
    Architectures:
      - x86_64
    Environment:
      Variables:
        CRUDTABLE_TABLE_NAME: !Ref CRUDTable
        CRUDTABLE_TABLE_ARN: !GetAtt CRUDTable.Arn
Resources:
  CreateFunction:
    Type: AWS::Serverless::Function
    Properties:
      Handler: create.lambdaHandler
      Policies:
        - DynamoDBWritePolicy:
            TableName: !Ref CRUDTable
        - DynamoDBCrudPolicy:
            TableName: !Ref CRUDTable
      Events:
        Api:
          Type: Api
          Properties:
            Path: /create
            Method: post
    Metadata:
      BuildMethod: esbuild
      BuildProperties:
        Minify: true
        Target: es2020
        Sourcemap: true
        EntryPoints:
          - create.ts
  ReadFunction:
    Type: AWS::Serverless::Function
    Properties:
      Handler: read.lambdaHandler
      Policies:
        - DynamoDBReadPolicy:
            TableName: !Ref CRUDTable
        - DynamoDBCrudPolicy:
            TableName: !Ref CRUDTable
      Events:
        Api:
          Type: Api
          Properties:
            Path: /read/{id}
            Method: get
            RequestParameters:
              - method.request.path.id
    Metadata:
      BuildMethod: esbuild
      BuildProperties:
        Minify: true
        Target: es2020
        Sourcemap: true
        EntryPoints:
          - read.ts
  UpdateFunction:
    Type: AWS::Serverless::Function
    Properties:
      Handler: update.lambdaHandler
      Policies:
        - DynamoDBWritePolicy:
            TableName: !Ref CRUDTable
        - DynamoDBCrudPolicy:
            TableName: !Ref CRUDTable
      Events:
        Api:
          Type: Api
          Properties:
            Path: /update/{id}
            Method: post
            RequestParameters:
              - method.request.path.id
    Metadata:
      BuildMethod: esbuild
      BuildProperties:
        Minify: true
        Target: es2020
        Sourcemap: true
        EntryPoints:
          - update.ts
  DeleteFunction:
    Type: AWS::Serverless::Function
    Properties:
      Handler: delete.lambdaHandler
      Policies:
        - DynamoDBCrudPolicy:
            TableName: !Ref CRUDTable
        - DynamoDBCrudPolicy:
            TableName: !Ref CRUDTable
      Events:
        Api:
          Type: Api
          Properties:
            Path: /delete/{id}
            Method: delete
            RequestParameters:
              - method.request.path.id
    Metadata:
      BuildMethod: esbuild
      BuildProperties:
        Minify: true
        Target: es2020
        Sourcemap: true
        EntryPoints:
          - delete.ts
  CRUDTable:
    Type: AWS::Serverless::SimpleTable
    Properties:
      TableName: CRUDTable

↓ポイントとなったことの備忘録

Globalsセクション

このセクションでは、以下のAWS SAMリソースについて全てのリソースに設定を継承します。
AWS::Serverless::Api
AWS::Serverless::Function
AWS::Serverless::HttpApi
AWS::Serverless::SimpleTable
AWS::Serverless::StateMachine
例えば各Lambda関数でランタイムやタイムアウト値など共通の設定を使用する際に各AWS::Serverless::Functionリソース内で定義を繰り返し記述せずに済みます。

パスパラメータを指定する

コード

  Events:
    Api:
      Type: Api
      Properties:
        Path: /read/{id}
        Method: get
        RequestParameters:
          - method.request.path.id

【ポイント】

  • 各関数定義のAPIイベントのプロパティでPath{id}とパスパラメータを指定する
  • 同じくプロパティでRequestParametersを指定する
  • 参考:Api - AWS Serverless Application Model

AWS SDK for JavaScript v3の準備

AWS SDK for JavaScript v3を使います。

npm install @aws-sdk/client-dynamodb

TypeScriptでDynamoDBにCRUDするコードを書いてみる

テーブルはこんな感じ

コードの流れ

  • DynamoDBClientを初期化する
    (例)const client = new DynamoDBClient({});
  • リクエスト内容を定義して変数に格納
    (例)const xxxRequest = ...
  • ↑で定義した値を引数に、リクエストクラスのインスタンスを作成
    (例)const command = new GetItemCommand(commans);
  • await client.send(command);でDynamoDB操作!

コードを書いてみる

項目の書き込み
import { DynamoDBClient, WriteRequest, BatchWriteItemCommand } from '@aws-sdk/client-dynamodb';

const client = new DynamoDBClient({ region: 'ap-northeast-1' });
const tableName = 'CRUDTable';
const writeRequests: WriteRequest[] = [
    {
        PutRequest: {
            Item: {
                id: { S: '1' }, // 実際はリクエストパラメータで受け取った値を使用
                name: { S: 'John' }, // 実際はリクエストボディで受け取った値を使用

            },
        },
    },
    {
        PutRequest: {
            Item: {
                id: { S: '2' }, // 実際はリクエストパラメータで受け取った値を使用
                name: { S: 'Alice' }, // 実際はリクエストボディで受け取った値を使用

            },
        },
    },
];

const command = new BatchWriteItemCommand({ RequestItems: { [tableName]: writeRequests } });
await client.send(command);
項目の読み取り
import { DynamoDBClient, GetItemCommandInput, GetItemCommand } from '@aws-sdk/client-dynamodb';

const client = new DynamoDBClient({ region: 'ap-northeast-1' });
const tableName = 'CRUDTable';

const getRequest: GetItemCommandInput = {
  TableName: tableName,
  Key: {
    id: { S: 1 }, // 実際はリクエストパラメータで受け取った値を使用
  },
};

const command = new GetItemCommand(getRequest);
const { Item } = await client.send(command);
項目の更新
import { DynamoDBClient, UpdateItemInput, UpdateItemCommand } from '@aws-sdk/client-dynamodb';

const client = new DynamoDBClient({ region: 'ap-northeast-1' });
const tableName = 'CRUDTable';

const updateRequests: UpdateItemInput = {
  TableName: tableName,
  Key: {
    id: { S: 1 }, // 実際はリクエストパラメータで受け取った値を使用
  },
  UpdateExpression: "set #name = :name",
  ExpressionAttributeNames: {
    "#name": "name",
  },
  ExpressionAttributeValues: {
    ":name": {
      S: "Katy", // 実際はリクエストボディで受け取った値を使用
    },
  },
};

const command = new UpdateItemCommand(updateRequests);
await client.send(command);
項目の削除
import { DynamoDBClient, DeleteItemInput, DeleteItemCommand } from '@aws-sdk/client-dynamodb';

const client = new DynamoDBClient({ region: 'ap-northeast-1' });
const tableName = 'CRUDTable';

const deleteRequests: DeleteItemInput = {
  TableName: tableName,
  Key: {
    id: { S: 1 }, // 実際はリクエストパラメータで受け取った値を使用
  },
};
const command = new DeleteItemCommand(deleteRequests);
await client.send(command);

改めて、コードを書く流れを振り返る

テーブル操作自体はDynamoDBClientsendメソッドにCommandを引数として渡す。Commandの定義については公式APIリファレンスを参照しつつ公式ドキュメントのコード例を参考に書いていく。この流れが基本になります。

まとめ

SDKを使用したコードを書こうとすると、いつも「あれ、どう書けばいいんだっけ?ドキュメントはどこ?結局どれが正しいの?」という気持ちになります。(SDKに限った話でもない…)
SDK for JavaScript v3のAPIリファレンスは見方が分かると読みやすいと感じました。とはいえ毎回忘れているので、基本の流れと何を参照すればいいんだっけ?をまとめてみました。
情報が膨大なドキュメントは読み慣れるのも一苦労なので、これからも一度覚えた読み方を備忘録としてまとめる習慣をつけたいと思います。

GitHubで編集を提案
Fusic 技術ブログ

Discussion