前回に引き続き、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