Serverless Frameworkの開発でDynamoDB Localを使う

2021.01.12
2021.01.17
Serverless Frameworkの開発でDynamoDB Localを使う

Serverless FrameworkでDynamoDBを用いる方法をご紹介します。


この記事では、最終的にServerless FrameworkでDynamoDB Localにmigrationを実行出来るようにします。

検証した環境

1 serverless 2.9.0
2 serverless-dynamodb-local 0.2.39

ローカル環境でDynamoDBを動かす環境を整える

DynamoDBをローカル環境で動かすための「DynamoDB Local」をAWSが用意してくれています
DynamoDB ローカル (ダウンロード可能バージョン) のセットアップ - Amazon DynamoDB

Serverless FrameworkのDynamoDB Localを使うためのパッケージを追加

手順が少しややこしいです。

  1. Serverless FrameworkでDynamoDB Localを使うパッケージを追加
  2. そのパッケージを使いDynamoDB Localをインストール

の順で実行します。


DynamoDB Localを先にインストールするのかな、と思ったら違うのですね。



そのためまず、Serverless FrameworkでDynamoDB Localを使うパッケージを追加

$ yarn add -D serverless-dynamodb-local



Serverless Framework(sls)でdynamodbを使えるようにする

Serverless Framework上でDynamoDB Localの操作が出来るようにserverless.ymlのpluginsに追記します。


この記述を行うことで、$npx sls dynamodb xxx(or $yarn run sls dynamodb xxx)コマンドが使えるようになります。

serverless.yml
plugins:
  - serverless-dynamodb-local #追加

DynamoDB Localをインストール

DynamoDB Localをインストールします。

$ npx sls dynamodb install

DynamoDBをインストールするためには$npx sls(プロジェクト内のServerless Frameworkのコマンド)を使います。



このコマンドを実行するとプロジェクトルート配下に.dynamodbフォルダが作られ、DynamoDB Localを実行するために必要な様々なファイルが追加されます。

projectRoot/
  .dynamodb/
    DynamoDBLocal_lib/
    third_party_licenses/
    DynamoDBLocal.jar
    ・・・
  package.json
  serverless.yml



プロジェクトメンバーには$npx dynamodb installを実行してもらえば良いので、.dynamodb/は.gitignoreに追加しておきましょう。

.gitignore
.dynamodb

DynamoDB Localを起動してみる

DynamoDB Localを起動するためserverless.ymlに最低限の記述を追加します

serverless.yml
custom:
  dynamodb:
    stages: #stagesについては後述
      - dev
    start:
      inMemory: true

inMemory: trueはメモリ上で実行する事でデータを永続化しません。


公式には↓のように書かれています

DynamoDB; will run in memory, instead of using a database file. When you stop DynamoDB;, none of the data will be saved. Note that you cannot specify both -dbPath and -inMemory at once.


データベースファイルを使用する代わりに、メモリ内で実行されます。 DynamoDB;を停止すると、データは保存されません。 -dbPathと-inMemoryの両方を同時に指定することはできないことに注意してください。(google翻訳)

Serverless DynamoDB Localより引用



公式にはそれ以外のオプションについても記載されていて参考になります。
serverless.ymlの記述内容ではなくCLIのコマンドのオプションについてのため違う部分もあるかもしれません

--port                    -p  Port to listen on. Default: 8000
--cors                    -c  Enable CORS support (cross-origin resource sharing) for JavaScript. You must provide a comma-separated "allow" list of specific domains. The default setting for -cors is an asterisk (*), which allows public access.
--inMemory                -i  DynamoDB; will run in memory, instead of using a database file. When you stop DynamoDB;, none of the data will be saved. Note that you cannot specify both -dbPath and -inMemory at once.
--dbPath                  -d  The directory where DynamoDB will write its database file. If you do not specify this option, the file will be written to the current directory. Note that you cannot specify both -dbPath and -inMemory at once. For the path, current working directory is <projectroot>/node_modules/serverless-dynamodb-local/dynamob. For example to create <projectroot>/node_modules/serverless-dynamodb-local/dynamob/<mypath> you should specify -d <mypath>/ or --dbPath <mypath>/ with a forwardslash at the end.
--sharedDb                -h  DynamoDB will use a single database file, instead of using separate files for each credential and region. If you specify -sharedDb, all DynamoDB clients will interact with the same set of tables regardless of their region and credential configuration.
--delayTransientStatuses  -t  Causes DynamoDB to introduce delays for certain operations. DynamoDB can perform some tasks almost instantaneously, such as create/update/delete operations on tables and indexes; however, the actual DynamoDB service requires more time for these tasks. Setting this parameter helps DynamoDB simulate the behavior of the Amazon DynamoDB web service more closely. (Currently, this parameter introduces delays only for global secondary indexes that are in either CREATING or DELETING status.)
--optimizeDbBeforeStartup -o  Optimizes the underlying database tables before starting up DynamoDB on your computer. You must also specify -dbPath when you use this parameter.
--migration               -m  After starting dynamodb local, run dynamodb migrations.



DynamoDB Localを起動してみます。

$ npx sls dynamodb start
Dynamodb Local Started, Visit: http://localhost:8000/shell
2021-01-11 16:21:21.519:INFO::main: Logging initialized @1156ms to org.eclipse.jetty.util.log.StdErrLog

http://localhost:8000/shell にアクセスすると、

起動出来ている事が確認出来ました!


stagesについて

私の環境だとserverless.ymlにcustom.dynamodb.stagesという項目を作っています。

serverless.yml
custom:
  dynamodb:
    stages:
      - dev

もしこの記述を行わなかった場合、

$ npx sls dynamodb start
Serverless: Skipping start: DynamoDB Local is not available for stage: dev

と表示されてDynamoDB Localが起動出来ないため、記載しています


そのため、stagesの部分を削除しても動く人は削除して問題ないと思います。



以下のissueを参考しました。
DynamoDB Local is not available for stage when loading from file · Issue #229 · 99x/serverless-dynamodb-local

migrationを実行する

テーブルの定義はserverless.ymlのresourcesに記載します。

Serverless Frameworkのresourcesの公式ページを参考にusersテーブルを定義します

serverless.yml
resources: # CloudFormation template syntax
  Resources:
    usersTable:
      Type: AWS::DynamoDB::Table
      Properties:
        TableName: users
        AttributeDefinitions:
          - AttributeName: email
            AttributeType: S
        KeySchema:
          - AttributeName: email
            KeyType: HASH
        ProvisionedThroughput:
          ReadCapacityUnits: 1
          WriteCapacityUnits: 1

email(文字列)をプライマリーキーのように扱うシンプルなテーブルですね。


先ほどのcustom.dynamodb.startmigrate: trueを追記します

serverless.yml
custom:
  dynamodb:
    stages:
      - dev
    start:
      inMemory: true
      migrate: true



これで改めてsls dynamodb startを実行してみると

$ npx sls dynamodb start
Dynamodb Local Started, Visit: http://localhost:8000/shell
2021-01-11 16:59:46.987:INFO::main: Logging initialized @1019ms to org.eclipse.jetty.util.log.StdErrLog
Serverless: DynamoDB - created table users

Serverless: DynamoDB - created table users

usersテーブルが作成出来た模様。



http://localhost:8000/shell にアクセスして左の欄に以下のコードを入力し、

var params = {
    TableName: 'users',
};
dynamodb.scan(params, function(err, data) {
    if (err) ppJson(err);
    else ppJson(data);
});

▶の再生マークをクリックします


データはないけど、エラーが表示されずテーブルが存在している事が確認出来ます!


seedデータを追加する

これだとinMemory: trueとしているため、DynamoDB Localが起動中にデータを追加しても$ npx sls dynamodb startをする度にDynamoDB Localのデータが消えてしまいます。


そのため、seedデータを用いてDynamoDB Local起動時に毎回データがある状態を作ります。



まずseed用のデータを用意します、jsonファイルはどこに作っても大丈夫です。

projectRoot/
  migrations/
    users.json
migrations/users.json
[
  {
    "id": 1,
    "email": "hoge@example.com"
  },
  {
    "id": 2,
    "email": "fuga@example.com"
  }
]



serverless.ymlを編集し、$ npx sls dynamodb startの時にseedデータを投入するようにします。

serverless.yml
custom:
  dynamodb:
    stages:
      - dev
    start:
      inMemory: true
      migrate: true
      seed: true
    seed:
      development:
        sources:
          - table: users
            sources: [ ./migrations/users.json ]



これで$ npx sls dynamodb startを実行すると

$ npx sls dynamodb start
Dynamodb Local Started, Visit: http://localhost:8000/shell
2021-01-11 19:53:38.178:INFO::main: Logging initialized @868ms to org.eclipse.jetty.util.log.StdErrLog
Serverless: DynamoDB - created table users
Seed running complete for table: users

Seed running complete for table: users

最後にSeedデータが投入されてそうです!



http://localhost:8000/shell にアクセスし、先ほどと同じコードを入力すると、

Seedデータが無事入りました!

DynamoDB Localの確認・操作を簡単にするdynamodb-adminについて

DynamoDB Localはここまでのようにhttp://localhost:8000/shellで操作をする事が出来ます。

しかし、お世辞にもsequelのようなGUIベースで簡単にデータを扱えるとは言い難いです。



そこで dynamodb-adminというパッケージを使う事で確認・操作を簡単に行えるようになります!



導入も大変ではないのでぜひ入れてみて下さい!


dynamodb-adminの記事を別途書いたのでご参考までに〜。

serverless.ymlに追記した部分全文

自分の備考録も兼ねて、
今回serverless.ymlに追記した部分と簡単なコメントを合わせて載せておきます

serverless.yml
# slsコマンドで `sls dynamodb install` などを実行する上でも必要
plugins:
  - serverless-dynamodb-local

custom:
  dynamodb:
    # dymanodb start時に起動が出来ないため記載、起動が出来るのであれば書かなくて問題ない
    stages:
      - dev
    # dymanodb start実行時の設定
    # 以下の場合
    # - データの永続化はしない(inMemory: true)
    # - migration実行とseedデータの投入をstart時に実行
    start:
      inMemory: true
      migrate: true
      seed: true
    seed:
      development:
        sources:
          - table: programs
            sources: [ ./migrations/users.json ]

# usersテーブルの定義
# migrationを実行した際にこの定義を元にテーブルを作る
resources:
  Resources:
    usersTable:
      Type: AWS::DynamoDB::Table
      Properties:
        TableName: users
        AttributeDefinitions:
          - AttributeName: email
            AttributeType: S
        KeySchema:
          - AttributeName: email
            KeyType: HASH
        ProvisionedThroughput:
          ReadCapacityUnits: 1
          WriteCapacityUnits: 1

おすすめ