前回に引き続き、AWS を触り始めて一ヶ月強の人間がサーバレス開発します。
脳内作戦会議、再び
静的コンテンツの公開までこぎつけたわけですが、
AWS を触り始めて一ヶ月強の僕には荷が重いままなわけで。
シンプルすぎる仕様は減らせない荷物なわけで。
適当な作戦が思いつかぬまま、下手の考え休むに似たり、と感心する頃には半日経過しちゃってるわけで。
![]() |
---|
- 作業a : S3 & CloudFront
- 作業b : API Gateway & Lambda & DynamoDB (本記事)
- 作業c : CloudWatch と サービス間の接続周り
API Gateway & Lambda & DynamoDB
しっかり休んだところで、やりたいことはコレだ。
- DynamoDB にテーブル作成
- Lambda で DynamoDB にデータ投入
- API Gateway から Lambda を呼び出す
DynamoDB
仕様を再確認する。
![]() |
---|
氏名、メールアドレス、電話番号の3属性、キーはメールアドレスね。
ということで公式チュートリアルを横目に、
![]() |
---|
がんばれ、がんばれ
![]() |
---|
がんばれ、がんばれ
![]() |
---|
ドカッと弁当がデカい男を登録できました。
満足。
Lambda
初心に帰れと言わんばかりのメニューアイコンを選択しつつ、
一から自分で頑張って作成するぜ、と意気込みます。
![]() |
---|
ランタイムはデフォルトで選択されていた Node.js
でいいや。
社内でも「わかりやすいと思うよー」とオススメされたし。
![]() |
---|
デフォルトの実行ロールのままだと
ログ出力以外に他のサービスとアレコレできないっぽい。
ということで IAM コンソールに寄り道してロールを作成。
![]() |
---|
Lambda に戻ってロールを選択して
![]() |
---|
作成すると
![]() |
---|
ひとまずできた、が、コレは枠組みでしかないわけで。
そして、Web 上に散らばる先人たちのコードをパッチワークするしかない僕なわけで。
一から自分で頑張ると意気込んだばかりだというのに。
const AWS = require('aws-sdk');
const documentClient = new AWS.DynamoDB.DocumentClient();
const util = require('util');
exports.handler = function(event, context, callback) {
console.log(util.inspect(event, false, null));
var input_email = (event.body.email) ? event.body.email : "*";
var input_name = (event.body.name) ? event.body.name : "*";
var input_phone = (event.body.phone) ? event.body.phone : "*";
var params = {
TableName: 'masklottery_entries',
Item: {
'email': input_email,
'name': input_name,
'phone': input_phone
},
ConditionExpression: 'attribute_not_exists(email)'
};
var response = {
"headers": {
"Content-Type": "application/json",
},
"body": ""
};
documentClient.put(params, function(err, data) {
if (err) {
console.log("***** failure *****");
console.log(err);
response.body = JSON.stringify(err);
callback(null, response);
} else {
console.log("***** success *****");
console.log(data);
response.body = JSON.stringify(data);
callback(null, response);
}
});
};
先程作成した DynamoDB にデータを追加するコードを作成してみた。
気を使ったトコロは ConditionExpression: 'attribute_not_exists(email)'
で、
意味は "キーがDB上に存在しない場合だけ(更新する)" という条件になるみたい。
![]() |
---|
同一メールアドレスでの申込は1回のみ
という仕様を取り入れてみました。
同一キーに対して DynamoDB は RDBMS で言う一意制約違反は発生せず上書き更新するらしいので。
テストデータもがんばって作成します。
![]() |
---|
葉っぱ咥えたアイツはどうかな?
![]() |
---|
よしよし、登録できた。
再度実行してみると、
![]() |
---|
うんうん、想定通りエラーになることを確認できた。
アレが2人もいたら迷惑ですよね。
DynamoDB でも確認してみる。
![]() |
---|
葉っぱ咥えたアイツの2人目は見当たらない。
満足。
API Gateway
「これからは HTTP API だ!」なノリで AWS 公式の説明が推してくるけど、
パラメータをアレヤコレヤできないので REST API を選択するわけで。
![]() |
---|
付け加えると、API Gateway からの作成ではなく、Lambda からのトリガーの追加で作成です。
イイ感じに入力の手間が減るのです。
![]() |
---|
メソッドが ANY だけど、DynamoDB に登録するだけの単一機能だし問題はないな。
次に統合リクエストから Lambda プロキシ統合の使用
のチェックを外して
![]() |
---|
パラメータマッピングを仕込む。
![]() |
---|
テンプレートのコードですか?
パッチワークですよ、一から自分で頑張りきれないですよ。
はい、デプロイ。
![]() |
---|
これで HTML の POST でリクエストするパラメータを Lambda で受け取れることになったわけです。
テストは POSTMAN
。
リクエストパラメータに語尾が「~ずら」のアノ人を仕込むずら。
![]() |
---|
200 でかえってきたずら。
![]() |
---|
再度実行すると
![]() |
---|
想定通りエラーになったずら。
念の為、DynamoDB も。
![]() |
---|
語尾が「~ずら」のアノ人の2人目もいない。
満足。
ということで今回の目的は達した。
株式会社メソドロジック
三嶋 圭 @k-mishima
参考
Class: AWS.DynamoDB.DocumentClient — AWS SDK for JavaScript
Node.js による Lambda 関数のビルド - AWS Lambda
【DynamoDB】updateItemで新規項目を追加しないようにする 〜条件付き書き込み(ConditionExpression)を使って〜 - Qiita
AWS API GatewayでContent-Type:application/x-www-form-urlencoded のPOSTデータを受け取り JSONに変換する - Qiita
【AWS】API GatewayのMapping Templateで、Key=ValueペアをJSONに変換する - Qiita