学習の備忘です。
やること
Dockerを利用してローカル環境でNode.js + DynamoDBの簡単なメッセージ記録システムを構築する。
Docker起動後には以下ページで動作確認ができます。
- メッセージ送信用ページ
http://localhost:8080
- DynamoDB-adminのページ
http://localhost:8001
フォルダ構造
dynamo_docker
├ docker-compose.yaml
├ dockerfile
└ main
├ app.js
├ createtable.js
├ config.json
├ package.json
├ public
└ index.html
dockerfile
FROM node:20
WORKDIR /app
COPY ./main/ .
RUN npm install
EXPOSE 8080
CMD ["node", "app.js"]
docker-compose.yaml
起動用のコマンド:docker-compose up -d
起動した後には、後述する node createtable.js を実行しテーブルを作成します。
composeのタイミングでテーブル作成を実行すると、接続ができないことがあったので起動後に手動で対応する形式にしました。
version: "3.8"
services:
dynamodb-local:
command: "-jar DynamoDBLocal.jar -sharedDb -dbPath ./data"
image: "amazon/dynamodb-local:latest"
container_name: dynamodb
ports:
- "8000:8000"
volumes:
- "./docker/dynamodb:/home/dynamodblocal/data"
working_dir: /home/dynamodblocal
dynamodb-admin:
image: aaronshaf/dynamodb-admin
container_name: dynamodb-admin
ports:
- "8001:8001"
environment:
- DYNAMO_ENDPOINT=http://dynamodb-local:8000
app-node:
build: .
container_name: node
depends_on:
- "dynamodb-local"
ports:
- "8080:8080"
package.json
{
"name": "express-app",
"version": "1.0.0",
"description": "Node.js Express Application",
"main": "app.js",
"scripts": {
"start": "node app.js"
},
"dependencies": {
"@aws-sdk/client-dynamodb": "^3.481.0",
"@aws-sdk/lib-dynamodb": "^3.481.0",
"express": "4.18.2"
},
"type": "module"
}
app.js
import express from "express";
import { join } from "path";
import pkg from "@aws-sdk/client-dynamodb";
import { DynamoDBDocumentClient, PutCommand } from "@aws-sdk/lib-dynamodb";
import config from "./config.json" assert { type: "json" };
const { DynamoDBClient } = pkg;
const app = express();
const port = 8080;
app.use(express.json());
app.use(express.static("public"));
const client = new DynamoDBClient(config.Dynamo);
const docClient = DynamoDBDocumentClient.from(client);
app.get("/", (req, res) => {
res.sendFile(join(__dirname, "public", "index.html"));
});
app.post("/send", async (req, res) => {
const messageText = req.body.message;
const timestamp = new Date();
timestamp.setHours(timestamp.getHours() + 9);
const jstTimestamp = timestamp.toISOString();
try {
await docClient.send(
new PutCommand({
TableName: "Messages",
Item: {
Timestamp: jstTimestamp,
MessageText: messageText
}
})
);
res.status(200).send("Message sent successfully");
} catch (error) {
console.error("Error saving message:", error);
res.status(500).send("Error saving message");
}
});
app.listen(port, () => {
console.log(`Server is running on port ${port}`);
});
createtable.js
import { CreateTableCommand, DescribeTableCommand, DynamoDBClient } from "@aws-sdk/client-dynamodb";
import config from './config.json' assert { type: 'json' };
const client = new DynamoDBClient(config.Dynamo);
async function main() {
try {
await client.send(new DescribeTableCommand({ TableName: "Messages" }));
console.log("Table already exists.");
} catch (error) {
if (error.name === 'ResourceNotFoundException') {
const createTableCommand = new CreateTableCommand({
TableName: "Messages",
AttributeDefinitions: [
{
AttributeName: "Timestamp",
AttributeType: "S"
}
],
KeySchema: [
{
AttributeName: "Timestamp",
KeyType: "HASH",
},
],
ProvisionedThroughput: {
ReadCapacityUnits: 1,
WriteCapacityUnits: 1,
},
});
try {
const response = await client.send(createTableCommand);
console.log("Table created:", response);
} catch (createError) {
console.error("Error creating table:", createError);
}
} else {
console.error("Error checking table existence:", error);
}
}
}
main();
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Message Sender</title>
</head>
<body>
<h1>Send a Message</h1>
<form id="messageForm">
<input type="text" id="messageText" placeholder="Enter message" required>
<button type="submit">Send</button>
</form>
<script>
document.getElementById("messageForm").onsubmit = async function(event) {
event.preventDefault();
const message = document.getElementById("messageText").value;
const response = await fetch('/send', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ message: message })
});
if (response.ok) {
console.log("Message sent!");
document.getElementById("messageText").value = '';
} else {
console.error("Failed to send message.");
}
};
</script>
</body>
</html>
config.json
DynamoDBlocalはエンドポイント以外の情報は適当な値で大丈夫です。
{
"Dynamo": {
"region": "us-west-2",
"credentials": {
"accessKeyId": "dummy",
"secretAccessKey": "dummy"
},
"endpoint": "http://dynamodb-local:8000"
}
}
簡易動作イメージ
テキストボックスに文字列を入力し、Sendボタンを押すと、DynamoDBlocalに送信時刻と内容が記録されます。
参考ドキュメント
以上どなたかのお役に立てば幸いです。