6
4

More than 3 years have passed since last update.

Lambda ↔ DynamoDB

Last updated at Posted at 2020-12-05

はじめに

Lambda から Rubyaws-sdk つかって DynamoDB な話です。何番煎じやねんと思いつつ、本日付のものは一つしかないだろうということで書きます。

image.png

ゴール的なもの

  • LambdaつかってサーバレスでクラウドネイティブなWebのバックエンドをブラウザ開発してみる
  • 今回はとりあえず、Lambda から Rubyaws-sdk つかって DynamoDB へというとこまでやる
  • 最終的には、AWSのあれやこれやのサービスをつなぎ合わせてアプリ作る

開発の流れ

  1. DynamoDBにテーブルつくる
  2. IAMでDynamoにアクセスできるようなロール作る
  3. ロールをLambdaに適用する
  4. Cloud9上で、aws-sdkつかってDynamoDBを叩くコード書く
  5. サーバへのデプロイとかテストとかもWebUIで簡単にできる(ショートカット覚えると快適)

以下、もうちょっと具体的にかいてみます1

DynamoDB

  1. コンソールから DynamoDB > テーブル > テーブルの作成 でテーブル名とプライマリーキーを決めてテーブル作る
  2. DynamoDB > テーブル > 項目 でWebUI上でレコード足せる(今回は、project-id name is-default というカラムを作成) image.png

考えるところはあんまりない

IAM

  1. AmazonDynamoDBFullAccessAWSLambdaDynamoDBExecutionRole の二つのポリシーをロール( ここでは LambdaDynamoDBという名前にした )にアタッチする

Lambda

  1. Lambda > 関数 > 関数の作成 > 一から作成ランタイムRuby2.7にして関数を作る( ここでは project という名前にした )
  2. Lambda > 関数 > project > アクセス権限 で先に作っておいたロール LambdaDynamoDB を付与する
  3. よし、関数にコード書き始めるよ image.png

Webバックエンドになるようなコードだと、以下の lambda_handler にロジックを書くことになる。

lambda_handler
def lambda_handler(event:, context:)
  # Your cool code is here
  { statusCode: 200, body: event }
end

ちなみに、event はクライアントから送ってくるデータが Hash で入っていて、context は関数のコンテキストが入っている。なにそれ?なときは puts context.inspect とかやって中身を見ましょう。初めのうちは気にしなくていいと思います。

context
#<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 します

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 が見たい

コード書いていると、pputs した 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,

シリーズ


  1. ここのページもステップ・バイ・ステップで手順がまとまっている 

  2. aws logs get-log-events --log-group-name /aws/lambda/project --log-stream-name '2020/12/01/[$LATEST]3cc66941ad844ba1afb5659ae677410b' --limit 100 みたいに ログ・グループとログ・ストリームの指定が必要だった。で、ログ・ストリームの値は関数実行ごとに毎回変わるのでめんどくさかった 

6
4
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
4