この記事について
Node.jsの概念や、Expressの使い方について詳しく書いてある記事ではありません。
ある程度の土台が用意してあるので、それを元に実際に手を動かして、TODOアプリを完成させることがこの記事の目的です。
pugファイルと仮処理を記述 の部分までは、コピペで進めていただいても大丈夫です。
TODOの処理を記述 の部分から実際に、Node.jsの様々な書き方を試していただけたらと考えております
Node.jsとは
Node.js はスケーラブルなネットワークアプリケーションを構築するために設計された非同期型のイベント駆動の JavaScript 環境です。
Node.js公式
非同期で処理が実行されるので、DBとの通信のような時間がかかる処理を実行する場合は async, await の記述が必要です。
Expressとは
Node.js のための高速で、革新的な、最小限のWebフレームワーク
Express公式
最小限の機能を持ったフレームワークです。基本的に利用するのは、ルーティングの機能かと思います。
LaravelやRailsのようなフレームワークの場合、プロジェクトを作成した時点でログイン機能、メール機能、など様々な機能が簡単に実装出来るように用意されていますが、Expressは全て自分でライブラリを選定して実装しないといけません。
そのため、フレームワーク自体の容量がとても小さいです。
事前準備
・ Git
・ Docker
手順1 dockerを利用して、Expressの実行環境を整える
スムーズにNode.jsの学習を進めるために、開発環境の構築をDockerで行います。
$ git clone https://github.com/KazukiSadasue/express-mysql-sample.git
$ cd express-mysql-sample
$ docker-compose up -d
上記のコマンドで、dockerコンテナが起動して、サーバーも立ち上がります。
http://localhost
に接続して、以下の画像のように表示されたら実行環境は整いました。
*もしかしたら、最初の1回目にサーバーの立ち上げ失敗するかもしれません。
その場合は、docker-compose restart
で再度立ち上げると治ると思います。
手順2 作成するアプリケーションについて
簡単なTODOアプリケーションを作成します。
ルーティングは以下のようにしようと思います。
パス | メソッド | 内容 |
---|---|---|
/ | GET | TODOトップ |
/create | POST | TODO作成 |
/done | POST | TODO完了 |
/delete | POST | TODO削除 |
TODOテーブルは以下のようにします。
カラム | 型 | 説明 |
---|---|---|
id | INTEGER | PRIMARYキー |
content | STRING | TODO内容(必須) |
isDone | Boolean | TODOの状態(必須、デフォルト0) |
deletedAt | DATETIME | 削除日時 |
createdAt | DATETIME | 作成日時 |
updatedAt | DATETIME | 更新日時 |
モデルの作成
テーブル設計から、TODOモデルを作成します。
modelsフォルダにtodo.jsを作成して、中身は以下のようにします。
todo.jsのコード
'use strict';
const loader = require('./sequelize-loader');
const Sequelize = loader.Sequelize;
const Todo = loader.database.define(
'todos',
{
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true,
allowNull: false,
},
task: {
type: Sequelize.STRING,
allowNull: false,
},
isDone: {
type: Sequelize.BOOLEAN,
allowNull: false,
defaultValue: 0,
},
}, {
paranoid: true,
freezeTableName: true,
}
);
module.exports = Todo;
次にapp.jsでモデルを読み込みます。
var logger = require('morgan');
var helmet = require('helmet');
// モデルの読み込み
+var Todo = require('./models/todo');
+Todo.sync();
モデルの作成が終わったら、Dockerコンテナを再度立ち上げます。
$ docker-compose restart
サーバーが再起動して、モデルに対応するテーブルが作成されます。
テーブルを確認するには、以下のコマンドを実行
$ docker exec -it mysql bash
# mysql -u root -p
Enter Password: パスワードは入力せずにEnter
mysql> use express-sample
mysql> show tables;
+--------------------------+
| Tables_in_express-sample |
+--------------------------+
| todos |
+--------------------------+
todosテーブルが作成されているのが確認出来ました!
pugファイルと仮処理を記述
TODOアプリのデザインはBootstrapを用いて作成しました。
以下のコードをコピペして配置してください。
views/index.pugのコード
extends layout
block content
h1 TODOアプリ
div
form(action="/create", method="post").form-inline.mb-3
div.form-group
input(type="text" name="task" placeholder="例: 晩御飯を作る").form-control
button(type="submit").btn.btn-primary 追加
div.mb-3
h2 TODO
form(name="todoform" method="post").mb-2
ul.list-group
each todo in todoTasks
li.list-group-item.px-5
input(name="todos", value=todo.id, type="checkbox", id=`todo-${todo.id}`).form-check-input
label(for=`todo-${todo.id}`).form-check-label #{todo.task}
if todoTasks.length
button.btn.btn-success(onclick="done()").mr-2 達成
button.btn.btn-danger(onclick="deleteTodo()") 削除
else
div TODOタスクはありません
div
h2 DONE
form(name="doneform" method="post").mb-2
ul.list-group
each done in doneTasks
li.list-group-item.px-5
input(name="todos", value=done.id, type="checkbox", id=`todo-${done.id}`).form-check-input
label(for=`todo-${done.id}`).form-check-label #{done.task}
if doneTasks.length
button.btn.btn-danger(onclick="deleteDone()") 削除
else
div DONEタスクはありません
script(src="javascripts/todo.js")
puglic/javascripts/todo.jsのコード
function done() {
document.todoform.action="/done";
document.todoform.submit();
}
function deleteTodo() {
document.todoform.action="/delete";
document.todoform.submit();
}
function deleteDone() {
document.doneform.action="/delete";
document.doneform.submit();
}
routes/index.jsのコード
var express = require('express');
var router = express.Router();
// TODOトップページ
router.get('/', async (req, res, next) => {
const todoTasks = [];
const doneTasks = []
res.render('index', {
todoTasks, doneTasks,
});
});
module.exports = router;
コードの記述が終わったら、 docker-compose restart
コマンドでコンテナを立ち上げなおします。
TODOの処理を記述
ここまで見た目の部分と、モデルの定義まで終わりました。
あとは、routes/index.js の部分に処理を書き加えるだけでTODOアプリが完成します。
ここから先は、色々と手を動かしてNode.jsの書き方に触れていただけたらと思います。
基本的な使い方
// ライブラリや、モデルの読み込みには、requireを利用する
const { Op } = require('sequelize');
// getのルーティング
router.get('/', () => {});
// postのルーティング
router.post('/', () => {});
Sequelizeの使い方
モデルの使い方は、 Sequelize公式ドキュメント を参考にします。
使い方の一部を抜粋してこちらに記述します。
// async を記述することで、非同期関数を定義する。
router.get('/', async (req, res, next) => {
// isDoneがtrueのデータを全件取得
// awaitを記述することで、DB処理の結果が返ってくるまで待つ
const todos = await Todo.findAll();
})
Sequelizeの使う上で、Node.jsは非同期通信であることに注意しないといけません。
async, awaitを利用して、DB処理が終わってから次の処理を行うようにしないと、不具合の原因となってしまいます。
上記の内容を参考に、TODOアプリを完成させていただけたらと思います。
最後に
TODOアプリ完成しましたでしょうか?
最終的な私の実装例を記述致します。
routes/index.jsの実装例
var express = require('express');
var router = express.Router();
const Todo = require('../models/todo');
const { Op } = require('sequelize');
// TODOトップページ
router.get('/', async (req, res, next) => {
const todos = await Todo.findAll();
const todoTasks = todos.filter(todo => todo.isDone === false);
const doneTasks = todos.filter(todo => todo.isDone === true);
res.render('index', {
todoTasks, doneTasks,
});
});
// TODO作成
router.post('/create', async (req, res, next) => {
await Todo.create({
task: req.body.task,
});
res.redirect('/');
});
// TODO完了
router.post('/done', async (req, res, next) => {
const todoModels = await getModelsByIds(req.body.todos);
for(const todo of todoModels) {
await todo.update({
isDone: true
});
}
res.redirect('/');
});
// TODO削除
router.post('/delete', async (req, res, next) => {
const todoModels = await getModelsByIds(req.body.todos);
for(const todo of todoModels) {
await todo.destroy();
}
res.redirect('/');
});
// リクエストのIDからTODOモデルを取得する
async function getModelsByIds(ids) {
if (typeof ids === 'string') {
ids = ids.split();
}
return await Todo.findAll({
where: {
id: {
[Op.in]: ids,
}
}
});
}
module.exports = router;
もっと説明の記述が必要、xxが分からない等ありましたらコメントお願い致します!
今回のコードの配置場所
https://github.com/KazukiSadasue/express-mysql-sample