DynamoDBの設計は発想も大事!? 異なるパラメータでも同じ応答をするWebAPIを作ってみた(API Gateway、Lambda、DynamoDB)
はじめに
サーバーレス開発部の藤井元貴です。
DynamoDBのレビュー会があり、そこで面白い使い方を知ったのでご紹介します。
実際に使う場合は、DynamoDBの設計をしっかりと実施してください。
ちなみに、DynamoDBのベストプラクティスはこちらです。
AWS公式が公開している資料も参考になると思います。
おすすめの方
- DynamoDBに興味がある
- AWS SAM(CloudFormation)でDynamoDBを使いたい
- AWS SAMでPathパラメータを使うAPIを作りたい
DynamoDBの面白い使い方
DynamoDBのユニークなKeyに対して、エイリアスレコード(別名用)を用意します。(エイリアスレコードは公式名称ではなく、勝手につけた名称です)
これにより、「Keyの表記ゆらぎ」があっても、DynamoDB内のレコードを特定できます!!
たとえば?
次のようなWebAPIがあるとします。
Path | Method |
---|---|
/color/{param} | GET |
この{param}
に対して、次のように異なるモノ(色名と色コード)を与えても、同じJSONを返却するように実装したいです。
- color/red
- color/ff0000
{ "name":"red", "name_ja":"赤", "r":255, "g":0, "b":0 }
red
やff0000
をそれぞれKeyとして、DynamoDBに同じ情報を持つのは無駄です。
name (Hash Key) | name_ja | r | g | b |
---|---|---|---|---|
red | 赤 | 255 | 0 | 0 |
ff0000 | 赤 | 255 | 0 | 0 |
そこで、DynamoDBのテーブルを次のように設計し、エイリアスレコード(別名用)を設けます。
name (Hash Key) | reference | name_ja | r | g | b |
---|---|---|---|---|---|
red | 赤 | 255 | 0 | 0 | |
ff0000 | red |
これにより、次の動作を行えば、「red」と「ff0000」で同じ内容を返却できます。
/color/red
の場合は、redを取得して返却する/color/ff0000
の場合は、ff0000を取得し、referenceを参照し、redを取得して返却する
目から鱗が落ちました。
エイリアスレコード以外の全データ取得は?
reference
以外の項目にGSI(グローバル・セカンダリ・インデックス)を設定すると取得できます。
今回はname_ja
にGSIを設定しています。
やってみた
環境
項目 | バージョン |
---|---|
macOS | High Sierra 10.13.6 |
AWS CLI | aws-cli/1.16.89 Python/3.6.1 Darwin/17.7.0 botocore/1.12.79 |
AWS SAM CLI | 0.10.0 |
Python | 3.6 |
サーバーレスなアプリの作成
AWS SAMを使用して作成します。
プロジェクトフォルダの作成
sam init --runtime python3.6 --name TryDynamoDB
Lambda関数とtemplateファイル
app.pyとtemplate.yamlは下記です。
見にくいですが、下記を一度に返却しています。
- pathで指定した1つのレコード
- 全てのレコード(エイリアスレコードを除く)
S3バケットの作成
コード等を格納するためのS3バケットを作成します。作成済みの場合は飛ばします。
aws s3 mb s3://cm-fujii.genki-sam-test-bucket
build
下記でビルドします。
sam build
package
コード一式をS3バケットにアップロードします。
sam package \ --output-template-file packaged.yaml \ --s3-bucket cm-fujii.genki-sam-test-bucket
deploy
デプロイします。
sam deploy \ --template-file packaged.yaml \ --stack-name TryDynamoDB \ --capabilities CAPABILITY_IAM
動作確認
DynamoDBのテーブルにItemを追加
まずはparam=name
のItemを追加します。
aws dynamodb put-item \ --table-name TryDynamoDB-ColorTable \ --item '{"name":{"S":"red"}, "name_ja":{"S":"赤"}, "r":{"N":"255"}, "g":{"N":"0"}, "b":{"N":"0"}}' aws dynamodb put-item \ --table-name TryDynamoDB-ColorTable \ --item '{"name":{"S":"green"}, "name_ja":{"S":"緑"}, "r":{"N":"0"}, "g":{"N":"255"}, "b":{"N":"0"}}' aws dynamodb put-item \ --table-name TryDynamoDB-ColorTable \ --item '{"name":{"S":"blue"}, "name_ja":{"S":"青"}, "r":{"N":"0"}, "g":{"N":"0"}, "b":{"N":"255"}}'
続いて、param=rgb
のItemを追加します。
aws dynamodb put-item \ --table-name TryDynamoDB-ColorTable \ --item '{"name":{"S":"ff0000"}, "reference":{"S":"red"}}' aws dynamodb put-item \ --table-name TryDynamoDB-ColorTable \ --item '{"name":{"S":"00ff00"}, "reference":{"S":"green"}}' aws dynamodb put-item \ --table-name TryDynamoDB-ColorTable \ --item '{"name":{"S":"0000ff"}, "reference":{"S":"blue"}}'
こうなりました。
WebAPIのエンドポイントを確認
Web画面ポチポチでも良いですが、せっかくなのでコマンドを使います。
$ aws cloudformation describe-stacks --stack-name TryDynamoDB --query 'Stacks[].Outputs' [ [ { "OutputKey": "HelloWorldApi", "OutputValue": "https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/Prod/color/{param}", "Description": "API Gateway endpoint URL for Prod stage for Hello World function" } ] ]
OutputValue
がWebAPIのエンドポイントです!
いざ、確認!
まずは、param=name
を確認します。
curl https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/Prod/color/red
結果はこちら。red
が取得できました。(\u8d64は「赤」です)
ついでに、「実体レコードのみ(3個)」も取得できました!
{ "get_item":{ "r":255, "b":0, "name":"red", "name_ja":"\u8d64", "g":0 }, "scan":[ { "r":255, "b":0, "name":"red", "g":0, "name_ja":"\u8d64" }, { "r":0, "b":0, "name":"green", "g":255, "name_ja":"\u7dd1" }, { "r":0, "b":255, "name":"blue", "g":0, "name_ja":"\u9752" } ] }
続いて、param=rgb
を確認します。
curl https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/Prod/color/ff0000
結果はこちら。red
が取得できました。(\u8d64は「赤」です)
同じ内容ですね!!
{ "get_item":{ "r":255, "b":0, "name":"red", "name_ja":"\u8d64", "g":0 }, "scan":[ { "r":255, "b":0, "name":"red", "g":0, "name_ja":"\u8d64" }, { "r":0, "b":0, "name":"green", "g":255, "name_ja":"\u7dd1" }, { "r":0, "b":255, "name":"blue", "g":0, "name_ja":"\u9752" } ] }
さいごに
DynamoDBは設計(使い方)次第でいろんな事ができると実感しました。設計力を磨いていきたいですね!