🧾 概要
本記事では、AWSの基本サービスだけを用いて、「名前+メッセージの投稿・保存・一覧表示」ができるWebアプリを構築した手順を紹介します。
Amplifyは使用していません。
※この記事はGpt4oが書いたものを一部人間が編集しています。実際に構築した際の手順もGpt4o製です。
※はじめは、AWSが公式に出しているチュートリアルを実施しようとしましたが、Amplifyまわりでエラーが出たため実施方法を変更しました。
✅ 構成図
[ブラウザ]
↓ fetch
[CloudFront] ← index.html
↓
[S3 (静的ホスティング)]
↓ fetch
[API Gateway]
↓ ↓
[Lambda (Save)] [Lambda (List)]
↓ ↓
[DynamoDB (保存先)]
📦 使用サービス
- Amazon S3(HTML/JSのホスティング)
- Amazon CloudFront(CDN配信)
- Amazon API Gateway(REST APIルーティング)
- AWS Lambda(ビジネスロジック)
- Amazon DynamoDB(NoSQLデータ保存)
🛠 ステップごとの手順
① Lambda 関数の作成
-
SaveMessageFunction
(POST保存用)とListMessagesFunction
(GET一覧用)を作成 - 実行ロールは Lambda 作成時に自動生成され、後から
AmazonDynamoDBFullAccess
を追加
🔹 SaveMessageFunction
import json, boto3, uuid
from datetime import datetime
table = boto3.resource('dynamodb').Table('messages')
def lambda_handler(event, context):
body = json.loads(event['body'])
item = {
'id': str(uuid.uuid4()),
'name': body.get('name', '匿名'),
'message': body.get('message', ''),
'timestamp': datetime.utcnow().isoformat()
}
table.put_item(Item=item)
return {
'statusCode': 200,
'headers': {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'Content-Type'
},
'body': json.dumps({'message': '保存しました!'})
}
🔹 ListMessagesFunction
import json, boto3
table = boto3.resource('dynamodb').Table('messages')
def lambda_handler(event, context):
response = table.scan()
return {
'statusCode': 200,
'headers': {'Access-Control-Allow-Origin': '*'},
'body': json.dumps(response["Items"])
}
② DynamoDB テーブル作成
- テーブル名:
messages
- パーティションキー:
id
(String)
③ API Gateway の設定
-
/message
リソースを作成 - POST →
SaveMessageFunction
に統合 - GET →
ListMessagesFunction
に統合 - 両方に CORS 有効化
- Lambda プロキシ統合:True
- ステージ名
dev
でデプロイ
④ S3バケット作成+index.html アップロード
- 静的ウェブサイトホスティング有効化
-
index.html
をアップロード - パブリックアクセスを許可(または OAI によるアクセス許可)
index.html
抜粋:
const baseURL = "https://{your-api-id}.execute-api.ap-northeast-1.amazonaws.com/dev";
document.getElementById("msg-form").addEventListener("submit", async (e) => {
e.preventDefault();
const name = e.target.name.value;
const message = e.target.message.value;
await fetch(`${baseURL}/message`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ name, message })
});
e.target.reset();
loadMessages();
});
async function loadMessages() {
const res = await fetch(`${baseURL}/message`);
const messages = await res.json();
const list = document.getElementById("message-list");
list.innerHTML = "";
messages.forEach(msg => {
const li = document.createElement("li");
li.textContent = `${msg.name}: ${msg.message}`;
list.appendChild(li);
});
}
window.onload = loadMessages;
⑤ CloudFront作成(S3をオリジンに)
- OAI または OAC を設定して S3 バケットにアクセス許可
- キャッシュポリシー:
CachingDisabled
- デフォルトルート:
index.html
👩💻 画面
こんな感じで、投稿したメッセージを一覧で確認できる。
🚧 トラブルシュートメモ
症状 | 対処 |
---|---|
Missing Authentication Token |
fetch先URLが間違っている(例:/message vs /messages ) |
NetworkError when attempting to fetch resource |
CORS未設定/Lambdaエラー |
messages.forEach is not a function |
response['Items'] を返していない/JSで .Items 抜き忘れ |
CloudWatchログに何も出ない | API Gateway に統合設定がされていない/デプロイ忘れ |
✨ 所感・学び
- Amplify を使わずに構成することで、各AWSサービスの役割を理解できた(所要時間2,3時間)
- タイポ(
/messages
と/message
)に最後までハマった、、、(所要時間20分くらい) - CloudWatch での
print(event)
print(response)
デバッグが超重要
🔚 おまけ:今後の拡張アイデア
- Cognito 認証を追加(ユーザー別にメッセージ管理)
- AppSync + DynamoDB + Lambda に移行して GraphQL 化
- S3への画像アップロード機能追加