はじめに
Lambda
から Ruby
で aws-sdk
つかって DynamoDB
な話です。何番煎じやねんと思いつつ、本日付のものは一つしかないだろうということで書きます。
ゴール的なもの
- LambdaつかってサーバレスでクラウドネイティブなWebのバックエンドをブラウザ開発してみる
- 今回はとりあえず、
Lambda
からRuby
でaws-sdk
つかってDynamoDB
へというとこまでやる - 最終的には、AWSのあれやこれやのサービスをつなぎ合わせてアプリ作る
開発の流れ
- DynamoDBにテーブルつくる
- IAMでDynamoにアクセスできるようなロール作る
- ロールをLambdaに適用する
- Cloud9上で、aws-sdkつかってDynamoDBを叩くコード書く
- サーバへのデプロイとかテストとかもWebUIで簡単にできる(ショートカット覚えると快適)
以下、もうちょっと具体的にかいてみます1
DynamoDB
- コンソールから
DynamoDB
>テーブル
>テーブルの作成
でテーブル名とプライマリーキーを決めてテーブル作る -
DynamoDB
>テーブル
>項目
でWebUI上でレコード足せる(今回は、project-id
name
is-default
というカラムを作成)
考えるところはあんまりない
IAM
-
AmazonDynamoDBFullAccess
とAWSLambdaDynamoDBExecutionRole
の二つのポリシーをロール( ここではLambdaDynamoDB
という名前にした )にアタッチする
Lambda
-
Lambda
>関数
>関数の作成
>一から作成
でランタイム
はRuby2.7
にして関数を作る( ここではproject
という名前にした ) -
Lambda
>関数
>project
>アクセス権限
で先に作っておいたロールLambdaDynamoDB
を付与する - よし、関数にコード書き始めるよ
Webバックエンドになるようなコードだと、以下の lambda_handler
にロジックを書くことになる。
def lambda_handler(event:, context:)
# Your cool code is here
{ statusCode: 200, body: event }
end
ちなみに、event
はクライアントから送ってくるデータが Hash で入っていて、context
は関数のコンテキストが入っている。なにそれ?なときは puts context.inspect
とかやって中身を見ましょう。初めのうちは気にしなくていいと思います。
#<LambdaContext:0x00000000017d3830 @clock_diff=1607145893186, @deadline_ms=1607146470672, @aws_request_id="ea9e9b24-aec1-49ab-8d91-3d8eacc8c3e7", @invoked_function_arn="arn:aws:lambda:us-east-2:578170637269:function:qiita", @log_group_name="/aws/lambda/qiita", @log_stream_name="2020/12/05/[$LATEST]04dae62a2b914b20a6097187ac047ec6", @function_name="qiita", @memory_limit_in_mb="128", @function_version="$LATEST">
適当にコード書いたら Save
> Deploy
> Test
> Edit data
な 開発サイクルに入ります。
Command | Shortcut |
---|---|
Save |
⌘ + s
|
Deploy |
⌘ + shift + u
|
Test |
⌘ + i
|
Edit data |
⌘ + j
|
コード
とりあえず、DynamoDB に対して CRUD するものを書いてみます
{
"project-id": 2,
"name": "Running",
"is-default": false
}
みたいなデータが送られてきた時に以下のように CRUD します
require 'json'
require 'aws-sdk-dynamodb'
def add_project(table, event)
table.put_item({ item: event })
end
def delete_project(table, event)
params = { table_name: table, key: { 'project-id': event['project-id'] } }
begin
table.delete_item(params)
rescue Aws::DynamoDB::Errors::ServiceError => error
puts error.message
end
end
def update_project(table, event)
params = {
table_name: table,
key: { 'project-id': event['project-id'] },
attribute_updates: {
name: {
value: body['name'],
action: "PUT"
}
}
}
table.update_item(params)
end
def list_project(table)
scan_output = table.scan({ limit: 50, select: "ALL_ATTRIBUTES" })
scan_output.items.each do |item|
keys = item.keys
keys.each do |k|
puts "#{k}: #{item[k]}"
end
end
end
def lambda_handler(event:, context:)
http_method = 'POST'
dynamodb = Aws::DynamoDB::Resource.new(region: 'us-east-2')
table = dynamodb.table('project')
case http_method
when 'GET' then list_project(table)
when 'PUT' then update_project(table, event)
when 'POST' then add_project(table, event)
when 'DELETE' then delete_project(table, event)
else 0
end
{ statusCode: 200, body: list_project(table) }
end
-
aws-sdk
で簡単に書くことができる -
Aws::DynamoDB::Resource
vs.Aws::DynamoDB::Client
についてはもう少し調べてみたい - HTTPメソッドごとに処理を切り替える部分は(今後、接続するであろう)API Gateway から Lamda に
context.http_method
という形で HTTPメソッド(GET/PUT/POST/DELETE)が送られてくることを想定(ベストプラクティスはなんだろう? CRUD 個々に関数ファイル分けるのが一般的?それだとAPI Gatewayの設定が増えてちょっとめんどくさそう) -
attribute_updates
よりUpdateExpression
を使いなさいという記載も見かけるので、後で変更も考えたい(個人的にはattribute_updates
の方が読みやすく感じるが)
STDOUT が見たい
コード書いていると、p
や puts
した STDOUT をみたくなる。手っ取り早い方法は、AWS CLI を使うことだと思う。Lambda のログは、デフォルトで Cloud Watch
に飛ばされているようで、以前はみるのがややめんどくさかった2 が、今は以下で簡単に最新のログをみることができる
aws logs tail /aws/lambda/project
やってみた感じ
- アカウントつくってからコンソールログインして、Lambda で Hello World まで 5 分くらい
- Lambda は最初のリリースから 10 年くらいたってるみたいなんですが、かなりこなれてきている印象
- WebUI での開発もいい感じ。Cloud9 の買収・サーバレス開発環境への統合がワークしていると思う。エディタ部分をフルスクリーンにして、
vim
キーバインド、ショートカット覚えると集中できる -
aws-sdk
つかって Dynamo へ簡単な CRUD 書くまでで1, 2時間って感じ。生産性はめっちゃいい
参考にしたサイト
Cheers,
シリーズ
- Lambda ↔ DynamoDB
- API Gateway ↔ Lambda ↔ DynamoDB
- Cognito ↔ API Gateway ↔ Lambda ↔ Dynamo
- Amplify [Hosting] ↔ API Gateway [REST] ↔ Lambda
- API GatewayでCORSを有効にするためにやったこと
- AmplifyのJavascript SDKでCognito認証からデータ取得まで