今回はAWSでサーバレスの基本の一つを紹介します。
POSTメソッドでDynamoDBへToDoを登録し、GETメソッドでDynamoDBからToDo一覧を取得するというアプリケーションを、Lambda関数・API Gatewayと組み合わせて作成します。
AWS management consoleを使ってGUIで構築していきます。
やりたいこと
ベーシックなサーバレス構成を構築することが目的ですが、そのためのアプリケーションとして、以下の2点の機能を備えたToDo管理のAPIを作成します。
- GET /tasks:登録タスク一覧を取得
- POST /tasks:タスクを登録
エラー発生時はCloudWatchの監視でアラートを受け取れるようにも設定します。
構成概要
使用する主なリソースは、API Gateway、Lambda、DynamoDBです。
Lambdaで異常が発生した際に通知できるよう、CloudWatchも構成に入れていきます。

DynamoDBの作成
まず取り掛かるのはDynamoDBの作成です。AWSコンソールでDynamoDBを開き、「テーブルの作成」をクリック。

テーブルの作成をしていきます。ここでは、テーブル名を「Tasks」、パーティションキーを「taskId」とします。後はデフォルトのまま作成。

テーブルが作成されました。

Lambdaの作成と権限付与
Lambdaの作成
次にLambda関数を作成していきます。「Lambda」→「関数の作成」と進み、「一から作成」を選択します。
関数名は「TodoFunction」とし、ランタイムはPythonの最新版を選択。

関数が作成されたら、コードを書いていきます。
import json
import boto3
import uuid
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('Tasks')
def lambda_handler(event, context):
# HTTP API形式に対応
method = event.get("requestContext", {}).get("http", {}).get("method", "")
if method == "GET":
res = table.scan()
return {
'statusCode': 200,
'body': json.dumps(res['Items'])
}
elif method == "POST":
body = json.loads(event.get('body', '{}'))
# ▼ ここでテストエラーを発動
if not body.get('title'):
raise ValueError("title parameter is required for POST method (test error)")
item = {
'taskId': str(uuid.uuid4()),
'title': body.get('title', 'No Title')
}
table.put_item(Item=item)
return {
'statusCode': 200,
'body': json.dumps({'message': 'Task added', 'task': item})
}
return {
'statusCode': 400,
'body': json.dumps({'error': 'Unsupported method'})
}
“Deploy”をクリック。

権限付与
次に、「設定」→「アクセス権限」→「実行ロール」で「ロール名」をクリックします。

IAM設定画面で、「許可を追加」→「ポリシーをアタッチ」

“AmazonDynamoDBFullAccess”を追加します。

ポリシーが正常にアタッチされました。

API Gatewayの作成
APIの作成
APIを作成していきます。「APIの作成」→「HTTP API」→「構築」と進みましょう。

API名は「TodoAPI」としておきましょう。
「統合」で「Lambda」を選択し、関数は先ほど作成したものを選択して「次へ」をクリック。

ルート設定をします。GETとPOST両方に”/tasks”と設定し、統合ターゲットは作成した関数を指定します。
「次へ」ボタンをクリック。

次のステージ定義はデフォルトで良いので、そのまま「次へ」。

最後に「作成」ボタンでAPIを作成します。

アクセスURLの取得
作成が完了したら、左ペインの「Stages」をクリックし、$defaultステージを選択すると、アクセス用のURLが表示されます。

CloudWatchの監視設定
最後にCloudWatchで監視設定をしましょう。
左ペインの「アラーム状態」から「アラームの作成」をクリックします。

「メトリクスと条件の選択」メニューで「メトリクスの選択をクリック」

「メトリクスの選択」で「Lambda」をクリックします。

次に「関数名別」を選択。

作成したLambda関数の「Errors」を選択し、「メトリクスの選択をクリック。

エラー発生時にアラームが発砲されやすい様に次の値で設定します。
- 統計:合計
- 期間:1分
- 発生条件:以上
- 閾値:1

SNSトピックがなければ新規作成し、「次へ」

アラーム名を設定し、「次へ」をクリックします。

設定を確認し、作成完了します。
動作検証
APIコール – GET
まずはGETを試してみましょう。Windows Powershellで以下のコマンドを実行します。
正常終了しますが、結果は何も返ってきません。
Invoke-RestMethod -Uri "<API Gatewayのアクセス用URL>/tasks" -Method GET
APIコール – POST
次にデータを入れるためにPOSTを実行します。Windows Powershellで以下のコマンドを実行します。
Invoke-RestMethod -Uri "<API Gatewayのアクセス用URL>/tasks" `
-Method POST `
-Body '{"title":"test"}' `
-ContentType "application/json"
成功すると次のような結果が返ります。
message task
------- ----
Task added @{taskId=8a9baac0-4925-45f9-a555-c2aee347e8fb; title=test}
念のために、DynamoDBにも値が入っているか見てみましょう。
DynamoDBの画面から対象テーブルを開き、「項目の探索」を見てみます。
同じ値が入っていることが分かります。

APIコール – GET(再度)
再度GETメソッドを実行し、値が取得できるかを見てみます。今度は次のような結果が返ってきて、POSTで入れた値を取得することができました。
taskId title
------ -----
8a9baac0-4925-45f9-a555-c2aee347e8fb test
エラー発生時の動き
エラー発生時にCloudWatchアラームが動作するようにしているので、そちらの動作も見ておきましょう。
今回、「POST時にパラメータ指定がない場合はErrorを発生させる」ロジックを入れているので、以下のコマンドを実行してみます。
Invoke-RestMethod -Uri "<API Gatewayのアクセス用URL>/tasks"
すると次のエラーが返ってきて、ログ上もエラーと認識されます。
Invoke-RestMethod : {"message":"Internal Server Error"}
発生場所 行:1 文字:1
+ Invoke-RestMethod -Uri "https://xxxxxxx.execute-api.xxxxxxx.amaz ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod]、WebException
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
1分以内に何度か実行し、アラームの条件を満たせば、SNSトピックのエンドポイントに通知が発砲されます。

まとめ
サーバレスの基本的な構造として、LambdaとDynamoDBによるタスク登録アプリケーションを作成し、API Gatewayを介して動作させてみました。
また、CloudWatchの設定により、エラー発生時にアラームが発砲される仕組みも構築しました。
お試しの方は、リソース残存による課金防止のため、作成したものは削除を忘れないようにしてください。

