【初心者向け】Boto3の使い方入門 ~Referenceを読んでDynamoDBにPutするLambdaを作ってみよう~

記事タイトルとURLをコピーする

垣見です。

プログラミング初心者のみなさん、「Boto3を使ってLambdaの開発をしろ」と言われたらどうしますか?
答えはすべてインターネット上のReferenceにあります。(ない時もあります)

結論

結論:Referenceを読めば書ける!

作成物の基本構成は以下の通り。

  1. boto3と必要ファイルをimportする
  2. それぞれのAWSサービス特有のClientを定義する
  3. 定義したClientに対し、どんな処理を実行させたいか指示する

Lambdaにする場合はさらに以下を考える

  1. lambda_handlerを定義して作る
  2. IAMロールやタイムアウト値に注意する

DynamoDBにPutするLambda:

例1(1つのアイテムをPut)

import boto3

client_1 = boto3.client('dynamodb')
tablename = 'employee-infomation'

def lambda_handler(event, context):
    client_1.put_item(
        TableName=tablename,
        Item={
            'ID': {'S': '1'},
            'Department': {'S': '営業部'},
            'Name': {'S': '鯖和 湧子'}
        }
    )
    return {
        'statusCode': 200,
        'body': 'Item added successfully'
    }

例2(3つのアイテムをPut)

import boto3

client_1 = boto3.client('dynamodb')
tablename = 'employee-infomation'

# アイテムデータ
items = [
    {'ID': {'S': '1'},'Department': {'S': '営業部'},'Name': {'S': '鯖和 湧子'}}, 
    {'ID': {'S': '2'},'Department': {'S': '総務部'},'Name': {'S': '和久 鯖太'}}, 
    {'ID': {'S': '3'},'Department': {'S': '経理部'},'Name': {'S': 'Scomber Japonicus'}}
]

# 各アイテムをDynamoDBに追加
def lambda_handler(event, context):
    for item in items:
        client_1.put_item(
            TableName=tablename,
            Item=item)
        print(f"item(ID:{item['ID']['S']})を追加しました")
    return {
        'statusCode': 200,
        'body': 'Item added successfully'
    }

はじめに

これまでプログラミング経験はほとんどなかった私ですが、AWS環境でLambda関数を使った開発をすることになりました。
現在進行形で色々躓いていますが、特に「Referenceを読む」というのが最初はいまいちつかめませんでした。

「このページがReferenceなんだな」という所まではわかっても、それをどう読み解いたらいいのか、どうコードに落とし込めばよいのかがわからなかったという具合です。

この記事では、同じようにプログラミングやBoto3に不慣れな人のために、Boto3のreferenceをどう読んで使えばいいのかをまとめていきます。

前半で基本的なReferenceの見方についてまとめ、後半ではPythonで実際に小さなLambdaコード例1, 2を書いて動かしてみます。

余談ですが、Boto3の読み方を勉強したらAWS CLIリファレンスも読めるようになりました。嬉しい。

対象

  • Boto3とは何か知りたい人
  • Boto3のReferenceが読める用になりたい人
  • Boto3/AWS上でのPythonプログラムが書ける・自走できるようになりたい人
  • Lambdaの基本の書き方が知りたい人
  • DynamoDBにアイテムをPutするLambdaを作りたい人

Boto3とは?

Boto3はAWS SDK for Pythonのライブラリです。AWSの各種サービスにPythonからアクセスするためのAPIが提供されています。

簡単に言うと、「AWSをPythonで簡単に動かすための呪文をいっぱい作ったよー!あなたのコード内でインポートすればその呪文が使えるようになるよー!」みたいなイメージで大丈夫かと思います。AWSのリソースをPythonで操作するためには必須のライブラリです。

ちなみにBoto3という名前はピンクのイルカ、【アマゾンカワイルカ(英名:Boto)】に由来しているそうです。かわいいですね。

そしていらすとやにはアマゾンカワイルカがあるそうです。すごいですね。

Boto3とAWS CLIの違い

どちらもAPIを使ってAWSを操作することが出来ます。

Boto3はPythonの関数の中の一つとしてふるまいます。あくまで「PythonからAWSを操作したいときはこう書いてね」のルールの集まりです。

Pythonなので、Lambdaで使用できるというのは大きなポイントです。また、Pythonで使うことが出来る機能(表作成など)を持つので、細やかに対応できます。

それに対し、AWS CLIはシェル(黒い画面のイメージです)に直接書き込む文字列です。

利用例としてはAWS CloudShellやローカルのUbuntu環境から直接コマンドを打ちこんだり、シェルスクリプト(打ち込むコマンドをまとめたファイル)として使う、などがあります。

Boto3のReference

Boto3の公式ドキュメントはこちらにあります。特にAvailable Servicesというセクションが頻繁に使用され、AWSの各サービスにアクセスする際のコード例やAPIリファレンスが詳細に書かれています。

初めてこれを見ると、どこをどう使えばよいのか迷ってしまうかもしれませんが、順を追って解説していきます。

referenceを読んでみよう

全体構成(最初は飛ばしても良いです)

まず、Boto3のreferenceページに行くと、左ペインにはいくつかの項目が表示されています。 https://boto3.amazonaws.com/v1/documentation/api/latest/index.html#

  • Quickstart: ローカルの環境にboto3をインストールする方法や設定が書いてあります。今回のブログはこの設定が必要ない、Lambda環境でのチュートリアルをします。
  • A Sample Tutorial: 実際にAmazon SQSを Boto3 で動かすコードの例がいくつかあります。キュー作成、既存のキュー取得、キューにメッセージプッシュ、 キューからのメッセージを処理、の4つの例が載っています。
  • Code Examples: よく使う操作のコードが書いてあるので、必要な操作を探すときは便利です。CloudWatch、DynamoDB、EC2、IAM、KMS、S3、Secrets Manager、SES 、SQS、が載っていました。
  • Developer Guide: Boto3の仕様や一般的に使う機能が書いてあります。後述Available Serviceは個別のAWSサービスと対応していますが、こちらには例外処理方法などがあります。一番最初は難しいかもしれないので後から読んでみてください。
  • Security: セキュリティ要件やコンプライアンスについて説明してくれています。
  • Available Services: 最も頻繁に使う場所です。多くのAWSサービスが並んでおり、それらに対してAPIを使って操作を行うための情報が詰まっています。まずはここから見てみましょう。
  • Core References:
    • Boto3 Reference:Boto3全体で良く呼び出す関数について説明する場所です。最初は「よく使うboto3.clientの書き方がある」と認識すればよいかと思います。その他はログ設定などの設定があります。
    • その他のReference:Classを使って細かい設定を行う方法がわかります。先述のAvailable Servicesが読めるようになるまでは気にしなくてよいかと思います。
  • Customization References: DynamoDBとS3の操作について、Classを使って細かく設定したい場合の書き方が載っています。

Available Servicesの見方

では、Available Servicesをクリックして見てみましょう。 https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/index.html

沢山のAWSサービス名が並んでいます

Available Servicesは、AWSの各サービスに対してBoto3で操作を行う際に(体感)最も参照する重要なページです。
各サービスごとのポータルページと、さらにその先の個別操作ページがあります。

ポータルページとboto3.client

●ポータルページについて

DynamoDBのポータルページ。下に各操作APIへのリンクがずらり

例えばDynamoDBを操作したい場合は、DynamoDBをクリックしてください。

そのサービスに関連する全ての操作方法やサンプルコードがまとめられているポータルページに飛びます。

https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb.html

このポータルでは、「DynamoDBをclientとして指定する方法」と「DynamoDB関連のすべての操作へのリンク」が書かれています。

boto3.clientとは

リンク群との間に以下のようなコードがあります。

import boto3
client = boto3.client('dynamodb')

import boto3はその名の通り、boto3のライブラリをインポートしてそのコード内で使えるようにしています。

次の行は、「ここから先clientと書いてあったらboto3のdynamodbの操作のことです」と示しています。

要は、「コード内でポータルページ配下のAPIを呼び出すための変数の指定」と考えてください。

ポータルページのリンク先では、client = boto3.client('dynamodb')という前提で参考コードが記述されています。

もちろん実際に開発するときはこんな書き方もOKです。

import boto3
dynamodb-client-1 = boto3.client('dynamodb')

dynamo-clientの部分には任意のわかりやすい識別子を入れていいということですね。自分はこれが良くわからずもにょっとしていました。

ちなみに正確には「ここから先clientとあったらboto3というルール集の中のclientという操作でdynamodbを使うことを示すよ」って感じでしょうか。

boto3.client()の()の中にはサービス名のdynamodbが入っていますが、必要であれば以下のような追加の情報を渡すこともできます。

client(service_name, region_name=None, api_version=None, use_ssl=True, verify=None, endpoint_url=None, aws_access_key_id=None, aws_secret_access_key=None, aws_session_token=None, config=None)

Session reference - Boto3 1.35.58 documentation

個別操作ページ

さらに配下のページに進むと、DynamoDBのAPIを使ってどう操作するかが詳細に解説されています。

たとえば、こちらのリンク先ではDynamoDBテーブルにアイテムを追加するためのput_itemというメソッドの使い方が紹介されています。

dynamodbのput_item

どのページも、基本的には以下のような構成になっています。

  • 題名の処理で何が行われるのかの説明
  • Request Syntax:AWS環境に対して送るコードの形式
  • Request Structure:Request Syntaxのパラメータの説明
  • Responce Syntax:AWSから帰ってくる情報の形式
  • Response Structure:Responce Syntaxのパラメータの説明
①説明

まず、説明によると、put_itemはDynamoDBのテーブルに新しいアイテムを作成するか、古いアイテムを新しいアイテムに置き換えてくれるそうです。アイテムを追加する場合、必須の属性は主キー属性のみともありますね。

②Request Syntax

Request Syntaxを見てみましょう。長いですが、始まりはこうなっています。

response = client.put_item(
    TableName='string',
    Item={
        'string': {
            'S': 'string',
            'N': 'string',
            'B': b'bytes',
            'SS': [
                'string',
            ],

最初の1行目ですが、ここではresponseという変数にclient.put_itemを入れています。

responseの後にリクエスト処理を入れることで、AWSから帰ってくる値(レスポンス)がresponseに代入されます。

このclientは先ほどのポータルページの記述で定義した識別子の意味です。事前定義していればdynamodb-client-1とかでも良い部分ですね。その文字列の後に、.put_item(を入れて始めるという訳です。

その後すごく長い文が続いていますが、とりあえず全部読む必要はないです。
基本的に、「string、bytesなどの小文字でのデータ型が書かれている部分が我々が自由に書き込めるところだ」ということだけ押さえておいてください。

True|False のように許容される選択肢を書いてある部分もあります。

③Request Structure

長いSyntaxの内実際にどこが必要か確認するために見るべきは、次のRequest Structure(グレーの枠の下のParametersと書いてある部分以降)です。
先ほどのSyntaxはオプション含めすべての書き方を網羅しているためとても長かったですが、こちらで書くべき必須項目がわかります。

[REQUIRED](必須)が付いている必須項目を使います。その部分をRequest Syntaxエリアから抜き出し、書き換えると良いです。

今回[REQUIRED](必須)がついているのはTableName (string) とItem (dict)ですね。

前者にはアイテムを格納するテーブルの名前かテーブルの Amazon リソース名 (ARN) を、後者には属性名と値のペア(ID=1, Name=Johnのようなイメージ)のマップを入れればよいようです。DynamoDBの主キー属性のみが必須とあり、Syntaxではデータ型ごとに設定してくれていますね。

(最初は「S」「N」「SS」すべてに何かデータを入れる必要があるのかと思いましたがそうではなく、何か書く場合は当てはまるデータ型を選んで必要な文だけ書くということでした。Itemの中の最初のstringが属性名で、その中のS/N/B...などでデータ型を設定し、データ型に続くstringが属性に対する値になるようです。正直ちょっとややこしかったです…)

その他オプションについては、必要であれば都度付け加えてください。

ということで、例えば「ID、Department、Name」のような属性のDynamoDB Table(employee-infomation)を作りたい場合、以下のようなコードがかけます。

コード例1:

import boto3

client_1 = boto3.client('dynamodb')
tablename = 'employee-infomation'

client_1.put_item(
    TableName=tablename,
    Item={
        'ID': {'S': '1'},
        'Department': {'S': '営業部'},
        'Name': {'S': '鯖和 湧子'}
    }
)

この時のItemはDynamoDBの一項目(DynamoDBコンソールで一行に見えるもの。ちなみにRDBではないので「レコード」とは言わない)です。その中にID:1、Department:営業部、Name:鯖和 湧子を入れています。

また、個別操作ページの最初にCreates a new item, or replaces an old item with a new itemとある通り、このput_itemメソッドでは1つのアイテムしか入れられません。

以下のような複数アイテムを入れる場合には、各言語のループ処理などをうまく使う必要がありそうです。

ID Department Name
1 営業部 鯖和 湧子
2 総務部 和久 鯖太
3 エンタープライズクラウド部 Scomber Japonicus

コード例2:

import boto3
client_1 = boto3.client('dynamodb')
tablename = 'employee-infomation'

# アイテムデータ
items = [
    {'ID': {'S': '1'},'Department': {'S': '営業部'},'Name': {'S': '鯖和 湧子'}}, 
    {'ID': {'S': '2'},'Department': {'S': '総務部'},'Name': {'S': '和久 鯖太'}}, 
    {'ID': {'S': '3'},'Department': {'S': '経理部'},'Name': {'S': 'Scomber Japonicus'}}
]

# 各アイテムをDynamoDBに追加
for item in items:
    client_1.put_item(
        TableName=tablename,
        Item=item)

さらに実際のパターンでは、何かの出力内容をもとに自動で入力する様にする処理がほとんどだと思います。その場合は上記の「items」をその入力内容と紐づける必要があります。

④Responce SyntaxとResponse Structure

Responce SyntaxとResponse Structureでは、レスポンスとして返ってくるときの型と解説を教えてくれています。
処理内容をキャッチしたいときだったり、putではなくget系の処理を実行したときだったりに、どんな形式のデータが返ってくるかがわかるので便利です。

ある処理のレスポンスのデータをさらにどこかの変数にする、などが可能になります。 基本的に見かたはRequestと同じなので割愛します。

【小ネタ】Boto3のresourceとclientの違い

昔は、Boto3のAPIを使うときにはboto3.resource()を使うのが一般的だったそうです。

しかし、最近ではresouceよりもclientを使うことが推奨されています。現在はresourceで書かれているコードも動きますが、今後は互換性がなくなる可能性があるかもしれないので、出来るだけclientを使いましょう。

(例えば古いブログなどを参考にする際は注意が必要です)

The AWS Python SDK team does not intend to add new features to the resources interface in boto3. Existing interfaces will continue to operate during boto3’s lifecycle. Customers can find access to newer service features through the client interface.
(訳)
AWS Python SDK チームは、boto3 のリソース インターフェイスに新しい機能を追加する予定はありません。既存のインターフェイスは、boto3 のライフサイクル中は引き続き動作します。お客様は、クライアント インターフェイスを通じて新しいサービス機能にアクセスできます。

実際にLambdaで確かめてみよう

百聞は一見に如かず。(ブログだとこの表現は微妙ですね。)

先ほどのコード例1, 2 をもとに、実際にLambda関数で動くコードを作ってみましょう。

DynamoDBの準備

先ほどのコード例は、指定したDynamoDBのテーブル(tablename = 'employee-infomation')に対してアイテムを入れるコードでした。
そのため、入れる先のDynamoDBを作っておく必要があります。

今回はテーブルはコンソールで作ってしまいますが、挑戦したい方はテーブルを作成するLambdaも一緒に作ってみてください。

こちらのcreate_table関数を使うことでコンソールで作るのと同等のことが出来るはずです。
(実は答えのようなものがCode Examplesにあります)

  • DynamoDBのコンソールに移動し、テーブルから「テーブルの作成」を選択します。

  • テーブル名とパーティションキーを入力する必要があります。前者は'employee-infomation'、後者はIDとしておきます。
  • 「テーブルの作成」をクリックします。

できました

Lambda関数の作成

  • AWSコンソールでLambdaのコンソール画面へ行きます
  • 「関数の作成」を選択し、名前と言語を入力して「作成」を押します(今回はtest-put-dynamodbPython 3.12を選択しました)。細かい設定は必要なければ今はいじらなくて大丈夫です。

  • Lambda関数の実行時間はデフォルトで3秒しかないので、時間がかかる処理は設定を伸ばしましょう。「設定」>「一般設定」>「編集」からタイムアウト値を好きな時間に延ばします。最初は1分くらいまでにしておいて、様子を見ながら後から調整するとよさそうです。

IAMロールの権限付与

Lambdaをデフォルト設定で作ると、都度個別のIAMロールが作成されます。ただ、このIAMロールにはLambdaのデフォルトポリシーしかついていないため、今回のLambdaに行わせたいDynamoDBに対するput item権限などは都度付与する必要があります。

  • 設定 > アクセス権限 > 実行ロール > ロール名 からIAMロールに直接飛べます。

  • 必要なIAMポリシーを付与します。今回はインラインポリシーで作成しましたが、ポリシーを使いまわしたい場合などはIAMポリシーで権限を作ってから付与しても良いです。今回は以下をコピペし、<アカウントIDを入力>を12桁のアカウントIDに置き換えて付与します。

    • 許可を追加 > インラインポリシーを作成 > JSONを選択・コピペ > 次へ > ポリシー名を入力 > ポリシーの作成
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "dynamodb:PutItem",
            "Resource": "arn:aws:dynamodb:ap-northeast-1:<アカウントIDを入力>:table/employee-infomation"
        }
    ]
}

  • コードのlambda_function.pyが開かれるはずです。

コーディング

Lambdaコード例1:

import boto3

client_1 = boto3.client('dynamodb')
tablename = 'employee-infomation'

def lambda_handler(event, context):
    client_1.put_item(
        TableName=tablename,
        Item={
            'ID': {'S': '1'},
            'Department': {'S': '営業部'},
            'Name': {'S': '鯖和 湧子'}
        }
    )
    return {
        'statusCode': 200,
        'body': 'Item added successfully'
    }

ついでにreturnとして帰ってくる部分も追加してみました。(なくても良いです)

このコードの return は、DynamoDBへのデータの書き込み(put_item)がエラーなく実行された場合にのみ実行されます。もし put_item の実行でエラーが発生するとその後のreturnには到達しないため、statusCode200は帰ってきません。
エラーが発生した場合には、Lambdaのデフォルトのエラーハンドリングによって、エラーメッセージが返されます。

returnメッセージの部分でさらにReferenceのResponce Syntaxをもとに欲しい値を指定すれば、例えば消費された容量ユニットのような値をカスタムで戻り値にすることもできます。

  • 以上のコードをlambda_function.pyにコピー&ペーストします
  • Deployを押します

テスト

  • Deployの下のTestボタンを最初に押す(または「Create test event」を選択する)と、テストイベントが作成されます。テストイベントとは、関数のテスト時に起こる事象のことで、入力としてLambda関数に渡される文字列を定義できます。もし関数の実行に特定の入力が必要な場合はここでカスタマイズできますが、今回は必要ないのでデフォルトのまま名前testeventを付けて作成します。

ちなみにLambdaテストイベント名にハイフンを入れるとなぜかエラーが出る

  • Testを押して先ほど作ったイベントtesteventを選択し、テストを実行します。

  • 下部の「OUTPUT」に結果が表示されます。print関数での出力やエラーメッセージがここに表示されます。詳しくや過去のログはCloudWatchからも見ることが出来ます。

  • もしここでエラーが出たら、メッセージを見ながら原因を調査してみましょう。体感、「実行時間が足りない」「IAM権限が足りない」というエラーが最も遭遇するイメージです。次点で「その関数は存在しない」ですかね。

    • 実行時間が足りない:デフォルトで3秒だったLambda関数の実行時間を、先ほど1分にしました。これより時間がかかる場合はタイムアウトエラーとなります。
    • IAM権限が足りない:Lambdaが何かするときに使うロールに権限が足りない場合です。先ほどDynamoDBのput権限を追加しましたが、足りないとAccess Deniedのようなエラーになります。
    • その関数は存在しない:Lambdaではローカルで実行できた関数がインポート・実行できないことがあります。この場合、リポジトリを引っ張ってきてあげる必要が有ります

エラーが出るとこんな感じにOUTPUTにログが出ます

  • エラー箇所と思われる場所を修正したら、再度テストします。

成功しました

  • DynamoDB側も見に行ってみます。項目を探索からテーブルを見ると、無事1件追加されていました。

コード例2も試してみる

コード例2の方も同様に試してみましょう。以下を先ほどのlambda_function.pyに入れて試すと、既に入っていた1件に加えて2件の項目が追加されます。

import boto3

client_1 = boto3.client('dynamodb')
tablename = 'employee-infomation'

# アイテムデータ
items = [
    {'ID': {'S': '1'},'Department': {'S': '営業部'},'Name': {'S': '鯖和 湧子'}}, 
    {'ID': {'S': '2'},'Department': {'S': '総務部'},'Name': {'S': '和久 鯖太'}}, 
    {'ID': {'S': '3'},'Department': {'S': '経理部'},'Name': {'S': 'Scomber Japonicus'}}
]

# 各アイテムをDynamoDBに追加
def lambda_handler(event, context):
    for item in items:
        client_1.put_item(
            TableName=tablename,
            Item=item)
        print(f"item(ID:{item['ID']['S']})を追加しました")
    return {
        'statusCode': 200,
        'body': 'Item added successfully'
    }

Testを実行すると…

成功しました!

For文の中にprintを入れたことで、Function Logsに追加したIDが出力されるようにしてみました。 こんな感じで、ログに出力する内容を選べたりもします。

DynamoDB側でも問題なくPutされています。

(ちなみにDynamoDBに既に登録していたID:1の鯖和 湧子さんについては、パーティションであるIDが同じ1が上書きされた扱いになっています。)

まとめ

最初はとても難しく感じて時間がかかりましたが、一度分かれば「なーんだ」と風に腹落ちしました。
リファレンスが読めるようになると世界が広がると感じています。

この記事が、同じように悩む方の参考になれば幸いです。

垣見(かきみ)(執筆記事の一覧)

2023年新卒入社 エンタープライズクラウド部所属

図解するのが好き。「サバワク」のアイキャッチ作成も担当しています