Quantcast
Channel: Node.jsタグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 8940

[Node.js勉強会]ExpressフレームワークでTODOアプリを作ろう

$
0
0

この記事について

Node.jsの概念や、Expressの使い方について詳しく書いてある記事ではありません。
ある程度の土台が用意してあるので、それを元に実際に手を動かして、TODOアプリを完成させることがこの記事の目的です。

pugファイルと仮処理を記述 の部分までは、コピペで進めていただいても大丈夫です。
TODOの処理を記述 の部分から実際に、Node.jsの様々な書き方を試していただけたらと考えております

今回作成する、TODOアプリの動作は以下のような形です。
express-comp.mov.gif

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で再度立ち上げると治ると思います。

express-first-step.png

手順2 作成するアプリケーションについて

簡単なTODOアプリケーションを作成します。
ルーティングは以下のようにしようと思います。

パスメソッド内容
/GETTODOトップ
/createPOSTTODO作成
/donePOSTTODO完了
/deletePOSTTODO削除

TODOテーブルは以下のようにします。

カラム説明
idINTEGERPRIMARYキー
contentSTRINGTODO内容(必須)
isDoneBooleanTODOの状態(必須、デフォルト0)
deletedAtDATETIME削除日時
createdAtDATETIME作成日時
updatedAtDATETIME更新日時

モデルの作成

テーブル設計から、TODOモデルを作成します。
modelsフォルダにtodo.jsを作成して、中身は以下のようにします。


todo.jsのコード
todo.js
'use strict';constloader=require('./sequelize-loader');constSequelize=loader.Sequelize;constTodo=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でモデルを読み込みます。

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のコード
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のコード
public/javascripts/todo.js
functiondone(){document.todoform.action="/done";document.todoform.submit();}functiondeleteTodo(){document.todoform.action="/delete";document.todoform.submit();}functiondeleteDone(){document.doneform.action="/delete";document.doneform.submit();}



routes/index.jsのコード
routes/index.js
varexpress=require('express');varrouter=express.Router();// TODOトップページrouter.get('/',async(req,res,next)=>{consttodoTasks=[];constdoneTasks=[]res.render('index',{todoTasks,doneTasks,});});module.exports=router;


コードの記述が終わったら、 docker-compose restartコマンドでコンテナを立ち上げなおします。

すると、以下のような状態になるかと思います。
express-second-step.png

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処理の結果が返ってくるまで待つconsttodos=awaitTodo.findAll();})

Sequelizeの使う上で、Node.jsは非同期通信であることに注意しないといけません。
async, awaitを利用して、DB処理が終わってから次の処理を行うようにしないと、不具合の原因となってしまいます。

上記の内容を参考に、TODOアプリを完成させていただけたらと思います。

最後に

TODOアプリ完成しましたでしょうか?
最終的な私の実装例を記述致します。


routes/index.jsの実装例
routes/index.js
varexpress=require('express');varrouter=express.Router();constTodo=require('../models/todo');const{Op}=require('sequelize');// TODOトップページrouter.get('/',async(req,res,next)=>{consttodos=awaitTodo.findAll();consttodoTasks=todos.filter(todo=>todo.isDone===false);constdoneTasks=todos.filter(todo=>todo.isDone===true);res.render('index',{todoTasks,doneTasks,});});// TODO作成router.post('/create',async(req,res,next)=>{awaitTodo.create({task:req.body.task,});res.redirect('/');});// TODO完了router.post('/done',async(req,res,next)=>{consttodoModels=awaitgetModelsByIds(req.body.todos);for(consttodooftodoModels){awaittodo.update({isDone:true});}res.redirect('/');});// TODO削除router.post('/delete',async(req,res,next)=>{consttodoModels=awaitgetModelsByIds(req.body.todos);for(consttodooftodoModels){awaittodo.destroy();}res.redirect('/');});// リクエストのIDからTODOモデルを取得するasyncfunctiongetModelsByIds(ids){if(typeofids==='string'){ids=ids.split();}returnawaitTodo.findAll({where:{id:{[Op.in]:ids,}}});}module.exports=router;


もっと説明の記述が必要、xxが分からない等ありましたらコメントお願い致します!

今回のコードの配置場所
https://github.com/KazukiSadasue/express-mysql-sample


Viewing all articles
Browse latest Browse all 8940

Trending Articles