🗂
【Task-PRG】ディレクトリ構造の確認と、タスク管理機能の実装手順
はじめに
アプリ開発全体の流れは、こちらの本にまとめています。
タスク管理アプリのディレクトリ構造と実装手順
『Task-PRG』のディレクトリ構造を確認し、実装手順を説明します。
ステップ1: ディレクトリ構造の確認
以下が現時点での『Task-PRG』プロジェクトのディレクトリ構造です。
ディレクトリ構造
/task-rpg
├── .github
│ └── workflows
│ └── deploy.yml
├── public
│ ├── icons
│ ├── index.html
│ ├── main.js
│ └── manifest.json
├── script
│ └── deploy_script.sh
├── styles
│ └── main.css
├── index.js
├── models
│ └── task.js
├── routes
│ └── tasks.js
├── package.json
└── package-lock.json
ステップ2: タスク管理アプリの機能実装手順
index.js
の設定
2.1 index.js
ファイルにサーバーの設定を記述します。
index.js
// モジュールをインポート
const express = require('express');
const mysql = require('mysql2');
const taskRouter = require('./routes/tasks');
const hostname = process.env.EC2_HOSTNAME || 'localhost';
// Express アプリケーションを作成
const app = express();
// JSONデータを扱うための設定
app.use(express.json());
// public フォルダから静的ファイルを提供する
app.use(express.static('public'));
// RDS接続の設定
const connection = mysql.createConnection({
host: process.env.DB_HOST,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME
});
connection.connect(err => {
if (err) {
console.error('Error connecting to the database:', err);
return;
}
console.log('Connected to the MySQL database');
});
// タスクルートの使用
app.use('/tasks', taskRouter);
app.listen(3000, () => {
console.log(`Server is running on http://${hostname}:3000`);
});
2.2 モデルの設定
models/task.js
ファイルを作成し、タスクモデルを設定します。
task.js
const connection = require('../db');
// タスクテーブルを作成するクエリ
const createTableQuery = `
CREATE TABLE IF NOT EXISTS tasks (
id INT AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(255) NOT NULL,
level INT NOT NULL,
completed BOOLEAN DEFAULT false
)
`;
// タスクテーブルを作成
connection.query(createTableQuery, (err, results) => {
if (err) {
console.error('Error creating tasks table:', err);
return;
}
console.log('Tasks table created or already exists');
});
module.exports = connection;
2.3 ルートの設定
routes/tasks.js
ファイルを作成し、CRUDルートを設定します。
tasks.js
const express = require('express');
const router = express.Router();
const connection = require('../models/task');
// 全てのタスクを取得
router.get('/', (req, res) => {
connection.query('SELECT * FROM tasks', (err, results) => {
if (err) {
res.status(500).json({ message: err.message });
return;
}
res.json(results);
});
});
// 新しいタスクを作成
router.post('/', (req, res) => {
const { title, level } = req.body;
const query = 'INSERT INTO tasks (title, level) VALUES (?, ?)';
connection.query(query, [title, level], (err, results) => {
if (err) {
res.status(400).json({ message: err.message });
return;
}
res.status(201).json({ id: results.insertId, title, level, completed: false });
});
});
// 特定のタスクを取得
router.get('/:id', (req, res) => {
const query = 'SELECT * FROM tasks WHERE id = ?';
connection.query(query, [req.params.id], (err, results) => {
if (err) {
res.status(500).json({ message: err.message });
return;
}
if (results.length === 0) {
res.status(404).json({ message: 'Cannot find task' });
return;
}
res.json(results[0]);
});
});
// タスクを更新
router.patch('/:id', (req, res) => {
const { title, level, completed } = req.body;
const query = 'UPDATE tasks SET title = ?, level = ?, completed = ? WHERE id = ?';
connection.query(query, [title, level, completed, req.params.id], (err, results) => {
if (err) {
res.status(400).json({ message: err.message });
return;
}
res.json({ message: 'Task updated' });
});
});
// タスクを削除
router.delete('/:id', (req, res) => {
const query = 'DELETE FROM tasks WHERE id = ?';
connection.query(query, [req.params.id], (err, results) => {
if (err) {
res.status(500).json({ message: err.message });
return;
}
res.json({ message: 'Task deleted' });
});
});
module.exports = router;
2.4 フロントエンドの設定
public/index.html
ファイルに基本的なUIを設定します。
index.html
<!DOCTYPE html>
<html lang="jp">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Task-RPG</title>
<link rel="manifest" href="/manifest.json">
<link rel="stylesheet" href="/styles/main.css">
</head>
<body>
<h1>Welcome to Task RPG!</h1>
<div id="task-list"></div>
<form id="task-form">
<input type="text" id="title" placeholder="Task Title">
<input type="number" id="level" placeholder="Task Level">
<button type="submit">Add Task</button>
</form>
<script src="/main.js"></script>
</body>
</html>
public/main.js
ファイルにタスクの取得、表示、作成、更新、削除機能を記述します。
main.js
document.addEventListener('DOMContentLoaded', () => {
const taskList = document.getElementById('task-list');
const taskForm = document.getElementById('task-form');
// タスクを取得して表示する関数
async function fetchTasks() {
const response = await fetch('/tasks');
const tasks = await response.json();
taskList.innerHTML = '';
tasks.forEach(task => {
const taskItem = document.createElement('div');
taskItem.className = 'task-item';
taskItem.innerHTML = `
<strong>Title:</strong> ${task.title}<br>
<strong>Level:</strong> ${task.level}<br>
<strong>Completed:</strong> ${task.completed ? 'Yes' : 'No'}
<br>
<button onclick="completeTask(${task.id})">Complete</button>
<button onclick="deleteTask(${task.id})">Delete</button>
`;
taskList.appendChild(taskItem);
});
}
// 新しいタスクを作成する関数
taskForm.addEventListener('submit', async (e) => {
e.preventDefault();
const title = document.getElementById('title').value;
const level = document.getElementById('level').value;
const response = await fetch('/tasks', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ title, level })
});
if (response.ok) {
fetchTasks();
}
});
// タスクを完了する関数
window.completeTask = async (id) => {
const response = await fetch(`/tasks/${id}`, {
method: 'PATCH',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ completed: true })
});
if (response.ok) {
fetchTasks();
}
};
// タスクを削除する関数
window.deleteTask = async (id) => {
const response = await fetch(`/tasks/${id}`, {
method: 'DELETE'
});
if (response.ok) {
fetchTasks();
}
};
// 初回ロード時にタスクを取得して表示
fetchTasks();
});
public/styles/main.css
ファイルにスタイルを記述します。
main.css
body {
font-family: 'Arial', sans-serif;
background-color: #f0f0f0;
margin: 0;
padding: 20px;
}
h1 {
text-align: center;
}
#task-list {
margin-top: 20px;
}
.task-item {
background-color: #fff;
padding: 10px;
margin-bottom: 10px;
border-radius: 5px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
#task-form {
display: flex;
flex-direction: column;
align-items: center;
}
#task-form input, #task-form button {
margin: 5px 0;
padding: 10px;
border-radius: 5px;
border: 1px solid #ccc;
}
#task-form button {
background-color: #007bff;
color: white;
cursor: pointer;
}
#task-form button:hover {
background-color: #0056b3;
}
ステップ3: デプロイ手順
-
GitHubリポジトリの設定:
以下の手順に従い、Github Actionsの設定とdeploy.yml
の作成を行います。
-
デプロイの実行:
GitHub Actionsが自動的にトリガーされ、EC2インスタンスにアプリケーションがデプロイされます。
bashコマンド
git add .
git commit -m "Add GitHub Actions for EC2 deployment"
git push origin main
以上で、EC2インスタンス上で動作し、AWS RDSをバックエンドとして利用するタスク管理機能のデモページが完成しました。
Discussion