🐰

AWS Lamdaで激安の個人開発を試みるハンズオン記録

2024/09/16に公開

記事要約と目的

【当記事を一言でまとめると】
lamdaとdynamamoDB触ったことない人が、lamdaでpostとget処理使ってHTML/JSから呼び出すwebアプリもどきを作ります。

【目的&動機】
通常はwebアプリを作る場合はEC2やECS使うのが一般的な気がしますが、lamdaとdynamoDBを使ってバックエンド処理のAPIを簡単に安く作れないか興味あったのでAWSの研修参加して行ったハンズオンを備忘録として当記事を書き残します。
他の方の記事「Next.js を S3 + CloudFront にデプロイする」を参照すると、s3でReactとNext.jsのフロントエンドできるので、s3とlamdaでReact/Next&lamdaのアプリを安く気軽に作りたい。本記事ではlamdaとdynamoDBでAPI作って、HTML/JSでcallするまでしか実施できていないのであしからず。素直にEC2使った方が、実は楽だったりコスト安かったりするかもしれません笑
今後検証します。

AWS Lambaとは

AWS Lamdaは関数をサーバーレスで実行できるもの
イベント(httpリクエストやファイルアップロード)によって関数実行が可能
json形式のデータを受け取って処理を実行する

Webアプリケーションの実行環境としての構成例
・Amazon API gateway + AWS Lamda + Amazon Dynamo DB

AWS Lambaを使ってみる

lambaのページを開いて関数の作成をクリック
任意の関数名と言語を選択して他の入力は任意。「関数を作成」ボタンクリック

テストボタンクリックするとテスト可能、初回のみテスト名を入力する

Amazon Dynamo DBでデーブルを作成する

DynamoDBのページに飛んで>左メニューのテーブル>テーブルの作成を押して
下記画面で任意の値を入力

lamdaからDynamoDBにアクセス(pythonでプログラムを書く)

import json
import boto3

dynamodb = boto3.resource('dynamodb')
TABLE_NAME = "Users"

def lambda_handler(event, context):
    table = dynamodb.Table(TABLE_NAME)

    # 入力データの生成
    input_name = "testuser01"
    input_location = "tokyo"

    # DynamoDBへのデータ保存
    table.put_item(
        Item={
            "name": input_name,
            "location": input_location
        }
    )
    result = {"msg": "Data Inserted"}

    return {
        "statusCode": 200,
        "body": json.dumps(result)
    }

プログラムを書いたらDeployボタンを押して反映する

反映終わったらtestボタンを押して実行し動作確認が可能。
しかし、まだdaynamoDBへのアクセス権限を付与していないので最初はエラーになる。

アクセス権限付与するために、「設定」>「アクセス権限」> ロール名をクリックする

許可を追加をクリックし、インラインポリシーを追加

プルダウンでDynamoDBを選択し、
putItem(データ書き込み用)とscan(データ取得)アクションを許可する
対象リソースは全てを選択し「次へ」ボタンをおす

任意のポリシー名を選択し、「ポリシーの作成」ボタンを押す

実行ロールに DynamoDB が追加されている

コードタブからTestボタンを押し実行する

データが想定通り登録されているかDynamoDB上で確認
「テーブルアイテムの検索」ボタンを押す

登録された右下にデータが表示される

lamdaでhttpリクエストを受け付けられるようにする

プログラムをhttpリクスト対応するように変更する

import json
import boto3

dynamodb = boto3.resource('dynamodb')
TABLE_NAME = 'Users'

def lambda_handler(event, context):
    table = dynamodb.Table(TABLE_NAME)
    http_method = event['requestContext']['http']['method']

    # HTTP POST Request - DynamoDBへのデータ保存
    if http_method == "POST":
        body = json.loads(event["body"])
        table.put_item(
            Item = {
                    "name": body["name"],
                    "location": body["location"]
                }
            )
        result = {"msg": "Data Inserted"}
        status_code = 200

    # HTTP GET Request - DynamoDBからデータ取得
    elif http_method == "GET":
        result = table.scan()
        status_code = 200

    return {
        'statusCode': status_code,
        'body': json.dumps(result),
        "headers": {
            'content-type': 'application/json'
        }
    }

関数URLを設定する

セキュリティ上はAWS_IAMを選択すべきだが、実験ものならNONEでOK
パブリック公開されるので、実験後すぐにLamba関数をすぐに削除すること

s3にアップロードするサイトからlamda関数が使えるように、
「オリジン間リソース共有(CORS)を設定」にチェック入れる

許可メソッドはGETとPOST選択

URLが公開されるのでURLクリックすると、ブラウザ上でGETメソッドが実行される

ブラウザで開くとGETメソッドで取得したデータが表示される

s3にアップロードしたHTMLやJSからAPIを読んでみる

テスト用のs3のバケットを作成する

index.html
<html lang="ja">
<head>
<meta http-equiv="content-type" charset="utf-8">
<title>lamdaのAPI call実験</title>
<link rel="style" href="style.css" type="text/css">
<script src="./index.js" type="text/javascript"></script>
</head>

<body>
<header>
<h1>lamdaのAPI call実験</h1>
</header>

<h2>Lamdaでサーバーレスアプリケーション開発</h2>

<p>Lamdaを使ってDynamoDBへデータ入力する</p>
<form id="postfrom">
   <input type="text" id="name" placeholder="氏名(Name)を入力">
   <input type="text" id="location" placeholder="地域(Location)を入力">
   <button class="btn" onclick="post()">データを入力する</button>
</form>

<hr>

<p>Lamdaを使ってDynamoDBへデータ取得して表示する</p>
<button onclick="get()">データを取得する</button>
<div id="content"></div>

</body>
</html>
index.js
const url="https://{自分で作成したlamdaのURL}.lambda-url.ap-northeast-1.on.aws/"

function post(){
    const formData = {
        name : document.querySelector('#name').value,
        location: document.querySelector('#location').value,
    }
    fetch(url, {
        mode: 'cors',
        method: "POST",
        headers: {
             "Content-Type" : "text/plain"
        },
        body: JSON.stringify(formData)
    })
    .then((response) => response.json())
    .then((data) => console.log(data))
    .catch((error) => console.log(error));
}

function get() {
    fetch(url, {
     mode: 'cors'
    })
    .then((res) => res.json())
    .then((data) => {
        console.log(data)
        const contentBlock = document.querySelector("#content");

        for (const item of data.Items){
            const listItem = document.createElement("div");
            listItem.append(`Name: ${item.name}, Location: ${item.location}`);
            contentBlock.appendChild(listItem);
        }
    })
}

s3をホームページとして使用する設定を行う

s3のプロパティタブをクリックし、静的ウェブサイトホスティングを有効化する




有効化完了

アクセス設定を行う

s3に置いたページにアクセスできるように、一時的にパブリックアクセスのブロックを解除する
(バブリックアクセスは非推奨、試験的に使うのであれば自端末のIPのみからアクセスできるように
バケットポリシーを下記のように記載)

{
	"Version": "2012-10-17",
	"Statement": [
		{
			"Sid": "Statement1",
			"Principal": "*",
			"Effect": "Allow",
			"Action": "s3:GetObject",
			"Resource": "arn:aws:s3:::lamda-api-test/*",
		"Condition":{
		    "IpAddress":{
		        "aws:SourceIp":"{自端末のIPアドレス}/32"
		    }
		 }
		}
	]
}

自端末のIPアドレスのグローバルIPは「ラッコツールズのIP確認」などのサイトで確認可能
※デザリングや家庭用wi-fiの場合は、毎回IP変わる可能性あるので自分のIP確認すること

s3に置いたページに実際にアクセスしてみる

ファイルをS3にアップロードした上で、

s3のプロパティタブの静的ウェブサイトホスティングのURLをクリックして公開中のページを開く

ネットに公開されたページ上でlamdaで作ったAPIを実行できるようになる

動作確認が完了したら最後に作ったlamdaやs3の削除する(もしくはIAM設定してきちんとアクセス制限かける)

Discussion