目次
はじめに
はじめまして!新入社員のタナミです。
今回は人生初の技術ブログということで真野 智之様の「コードで学ぶAWS入門」の第13章をやってみました。
本来はCDKを利用して行うのですが、私はAWSのマネージドコンソールを使用して作成したので
同じくマネージドコンソールを使用して作成したい方に向けてに少しでも参考になればと思います。
「コードで学ぶAWS入門」はこちらをご覧ください!
構成図を確認しよう
今回作成する俳句SNS「Bashoutter」の構成図は以下の通りです。
Mano, T. (2021, June 14). コードで学ぶAWS入門.https://tomomano.github.io/learn-aws-by-coding
Lambdaを作ろう
まずは4つのLambda関数GET、POST、DELETE、PATCHを作成します。
ランタイムはPython3.14を選択し、それぞれのLambdaのリソース名は以下のようにしました。
tanami-haiku-get
tanami-haiku-post
tanami-haiku-delete
tanami-haiku-patch
共通の設定
次にロールを作成し4つのLambda全てに同一のロールを割り当てます。
ロールにはAmazonDynamoDBFullAccessのポリシーをアタッチしておきましょう。
これによりLambda→DynamoDBへとアクセスすることが出来ます!
また、タイムアウト秒を30秒に変更しておきます。
Lambdaのコード
さて、Lambdaのガワを用意することが出来たので次に中身の実装です。
元サイト様のGitHubを参考にコードを作成します。
それぞれのLambdaに設定するコードは以下の通りです。
tanami-haiku-get
import json
import os
import decimal
import boto3
# DynamoDB設定
ddb = boto3.resource("dynamodb")
table = ddb.Table("tanami-haiku-table")
# CORS設定
HEADERS = {
"Access-Control-Allow-Origin": "*",
}
# Decimal対応のJSONエンコーダー
class DecimalEncoder(json.JSONEncoder):
def default(self, o):
if isinstance(o, decimal.Decimal):
return float(o)
return super(DecimalEncoder, self).default(o)
def lambda_handler(event, context):
"""
handler for GET /haiku
"""
try:
response = table.scan()
status_code = 200
resp = response.get("Items")
except Exception as e:
status_code = 500
resp = {"description": f"Internal server error. {str(e)}"}
return {
"statusCode": status_code,
"headers": HEADERS,
"body": json.dumps(resp, cls=DecimalEncoder)
}
tanami-haiku-post
import json
import os
import uuid
from datetime import datetime, timezone
import boto3
# DynamoDB設定
ddb = boto3.resource("dynamodb")
table = ddb.Table("tanami-haiku-table")
# CORS設定
HEADERS = {
"Access-Control-Allow-Origin": "*",
}
def lambda_handler(event, context):
"""
handler for POST /haiku
"""
try:
body = event.get("body")
if not body:
raise ValueError("Invalid request. The request body is missing!")
body = json.loads(body)
for key in ["username", "first", "second", "third"]:
if not body.get(key):
raise ValueError(f"{key} is empty")
item = {
"item_id": uuid.uuid4().hex,
"username": body["username"],
"first": body["first"],
"second": body["second"],
"third": body["third"],
"likes": 0,
"created_at": datetime.now(timezone.utc).isoformat(timespec="seconds")
}
response = table.put_item(Item=item)
status_code = 201
resp = {"description": "Successfully added a new haiku"}
except ValueError as e:
status_code = 400
resp = {"description": f"Bad request. {str(e)}"}
except Exception as e:
status_code = 500
resp = {"description": str(e)}
return {
"statusCode": status_code,
"headers": HEADERS,
"body": json.dumps(resp)
}
tanami-haiku-delete
import json
import os
import boto3
# DynamoDB設定
ddb = boto3.resource("dynamodb")
table = ddb.Table("tanami-haiku-table")
# CORS設定
HEADERS = {
"Access-Control-Allow-Origin": "*",
}
def lambda_handler(event, context):
"""
handler for DELETE /haiku/{item_id}
"""
try:
path_params = event.get("pathParameters", {})
item_id = path_params.get("item_id", "")
if not item_id:
raise ValueError("Invalid request. The path parameter 'item_id' is missing")
response = table.delete_item(
Key={"item_id": item_id}
)
status_code = 204
resp = {"description": "Successfully deleted."}
except ValueError as e:
status_code = 400
resp = {"description": f"Bad request. {str(e)}"}
except Exception as e:
status_code = 500
resp = {"description": str(e)}
return {
"statusCode": status_code,
"headers": HEADERS,
"body": json.dumps(resp)
}
tanami-haiku-patch
import json
import os
import boto3
# DynamoDB設定
ddb = boto3.resource("dynamodb")
table = ddb.Table("tanami-haiku-table")
# CORS設定
HEADERS = {
"Access-Control-Allow-Origin": "*",
}
def lambda_handler(event, context):
"""
handler for PATCH /haiku/{item_id}
"""
try:
path_params = event.get("pathParameters", {})
item_id = path_params.get("item_id", "")
if not item_id:
raise ValueError("Invalid request. The path parameter 'item_id' is missing")
response = table.update_item(
Key={"item_id": item_id},
UpdateExpression=f"SET likes = likes + :inc",
ExpressionAttributeValues={
':inc': 1,
}
)
status_code = 200
resp = {"description": "OK"}
except ValueError as e:
status_code = 400
resp = {"description": f"Bad request. {str(e)}"}
except Exception as e:
status_code = 500
resp = {"description": str(e)}
return {
"statusCode": status_code,
"headers": HEADERS,
"body": json.dumps(resp)
}
DynamoDBのテーブルを作ろう
次にDynamoDBのテーブルを作成していきます。
テーブル名を設定し、パーティションキーをitem_idと設定します。
また、Auto ScalingをOFFにして
書き込みキャパシティーと読み込みキャパシティーをどちらも1に設定することで万が一の料金の跳ね上がりを防止出来ます!
動作確認テスト~その1~
さて、LambdaとDynamoDBを作成することが出来たので
GETとPOSTの動作確認を行いましょう!
Lambdaではテストイベントを作成しテストを実行することで簡単に動作を確認することが出来ます。
それでは早速やってみましょう!
tanami-haiku-postで俳句の作成
Lambdaに戻りテストイベントを作成します。
イベントJSONにコードを記入してテストを実行します
イベントJSONのコードは下記の通りです。
{
"body": "{\"username\": \"tanaka_taro\", \"first\": \"春風に\", \"second\": \"桜散りゆく\", \"third\": \"静寂かな\"}"
}
ログを確認しましょう。
以下のようなログが出力されていれば成功です!
tanami-haiku-getで俳句の確認
先ほどと同様にテストを実行します。
イベントJSONのコードは下記の通りです。
{
"httpMethod": "GET",
"path": "/haiku",
"headers": {
"Content-Type": "application/json"
}
}
こちらも同様にログの確認をしましょう。
DynamoDBでも俳句の確認をしよう
さてLambda上では俳句の確認を行えましたが
念のためDynamoDBでも作成された俳句の確認を行いましょう。
項目スキャンまたはクエリを実行することで作成された俳句が確認出来ます。
これでLambdaからDynamoDBまでの連携を確認することが出来ました!
S3を作ろう
さて、LambdaとDynamoDBを作成することが出来たので
次にS3を使ってWebページ部分を作成します。
バケット名を設定しパブリックアクセスを全て許可します。
ウェブサイトをホスティングさせよう
S3が作成出来たら静的ウェブサイトホスティングを許可し
インデックスドキュメントにindex.htmlを指定します。
Lambdaのコードと同様に元サイト様のGitHubからbashoutter/gui/distのディレクトリに含まれるファイルを全てアップロードします。
バケットポリシーを設定しよう
次にバケットポリシーを設定します。
バケットポリシーを適用することでWebサイト上から先ほどアップロードしたindex.htmlにアクセス出来るようになります。
バケットポリシーは以下の通りです。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicFullAccess",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::作成したバケット名/*"
}
]
}
APIGatewayを作ろう
最後にAPIGatewayを作成しましょう
APIGatewayを作成することでWebサイト上から俳句の閲覧及び投稿が可能になります!
APIを作成からRESTAPIを選択し作成します。
APIGatewayとLambdaを連携しよう
APIGatewayを作成完了後にリソースを作成から/haikuと/haiku/{item_id}を作成します。
メソッドを作成から/haikuにGETとPOSTのメソッドを作成し
/haiku/{item_id}にDELETEとPATCHのメソッドを作成します。
それぞれに各Lambdaを割り当てLambdaプロキシ統合をONにします。
最後にCORSを有効にするから/haikuと/haiku/{item_id}のどちらもCORSを有効にしておきましょう。
APIGatewayをデプロイしよう
最後にAPIをデプロイから作成したAPIGatewayを有効化させましょう。
ステージ名はprodとしておきます。
またデプロイ後のURLは忘れずにコピーしておきましょう!
動作確認テスト~その2~
いよいよ最後の動作確認を行います!
Webサイト上からS3のindex.htmlにアクセスしAPI EndPoint URLに先ほどコピーしたAPIGatewayのURLを貼り付けREFRESHをクリックします。
動作確認テスト~その1~で作成した俳句が表示されているはずです。
更に俳句を入力しPOSTしてREFRESHを押すことでWebサイト上で俳句を投稿することが出来ます!
最後に
いかがだったでしょうか。
今回ハンズオンとして扱った「コードで学ぶAWS入門」はこの俳句SNS以外にも、AWSの基本からAWSサービスを使ったチャットボットの作成まで幅広くAWSの基礎を学ぶことが出来るので非常にオススメです。
また、さらにLambdaのハンズオンに触れたい場合はAWS公式のハンズオンもあり、こちらは動画付きで丁寧に解説してあるのでオススメです。
ではまた次のブログでお会いしましょう!
よろしくお願いします。