15
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Node.js基本編 Express+SQLiteで超定番のTo Doメモアプリを作る

Last updated at Posted at 2021-05-02

本編はNode.js+Express+SQLiteを使って、DataBaseにCRUDできるアプリを作る工程を紹介をします。実際に作るのは定番中の定番、To Doメモアプリですので難しい事は一切しない初学者向けです。

掌田津耶乃 著のNode.js超入門がベースです。

##一応念のため、CRUDとは
Create(登録) 新しいデータを登録する。
Read(参照) レコードをテーブルから取り出す。
Update(更新) レコードの内容を更新する。
Delete(削除) レコードを削除する。

##一応念のため、Webアプリケーションとは(サイトとの違い)
Webサイト=情報を提供
静的ファイルをホスティングしてるだけで、誰が見ても同じ情報を表示する。

Webアプリケーション=情報のやり取り
ユーザーがフォーム入力、送信、など様々な行動をアプリケーション上で行える。ユーザーが送信したデータを処理して結果を表示する。

####では実際にやっていきましょう。大きく分けて4ステップで説明していきます。
**Step1:**Node.jsアプリ基盤構築
**Step2:**DataBase構築
**Step3:**ページを用意
**Step4:**CRUD処理を実装

前提条件:Node.jsはインストールしておいてください。インストールの仕方はこちらを参考

####Step1:Node.jsアプリ基盤構築
入門編でも紹介したアプリケーションのひな形を生成してくれる便利なツールのExpress-Generatorをインストールしましょう。

npm install -g express-generator

これでグローバルにインストールされてシステム全体でExpress-Generatorが使えます。

ではアプリを作っていきます。 express -e アプリ名

express -e todo-app

これで「todo-app」という名前のディレクトリができ、各種フォルダも自動で作られます。
スクリーンショット 2021-05-01 19.23.19.png

Express-Generatorはデフォルトで各種パッケージを入れておいてくれるので、プロジェクトディレクトリに入り、npm installをして全部インストールしましょう。

cd todo-app
npm install

そして、今回DataBaseを扱う為に必要なSQLite3は、別途インストールが必要です。

npm install --save sqlite3

各ディレクトリの説明をざっくりと、
bin/
アプリを実行する為のコマンドとなるファイルが保管されてます。基本的に触りません。

public/
CSSや画像などをこの中に置きます。

routes/
このディレクトリではルート(URL)ごとの処理がまとめらています。
用意するページのアドレスごとにここにファイルを追加します。

views/
画面側を作る上で必要なViewファイルを置きます。サーバーサイドからこのファイルに対して値を渡すことが出来ます。

node_modules/
npm installするとパッケージ類はこのディレクトリに入ってきます。基本的に触りません。

app.js
これがメインプログラムです。Expressの設定周りを担っています。

これでアプリの基盤はひとまず完成です。Express-Generatorを使うとすごい楽ですね。

####Step2:DataBase構築
続いてDataBaseの構築です。DB Browser for SQLiteを使います。
*DB Browser for SQLiteはSQLiteのデータベースをGUIで管理することができるツールです。 導入方法はこちらを参考にしてください、簡単です。

まずDataBaseファイルを作ります。
「新しいデータベース」をクリックします
ファイル名は「memo_data」として、保存先はtodo-appフォルダ直下です。これでmemo_data.db / memo_data.sqlite3というファイルが作られます。

次にテーブルを作ります。
今回は超シンプルなメモアプリなので、メモを格納するテーブル(テーブル名:memos)を一つだけ用意ます。

次にカラムを作ります
カラムは以下2点に留めておきます。
・id -これは編集、削除するのに指定する為に必須
・text
(もっとあっていいですが今回はミニマムな実装に留めます)
スクリーンショット 2021-05-02 22.59.07.png

最初に何個かダミーデータを登録しておきましょう。

普通のアプリ開発では必要なデータを洗い出して、テーブル、カラムをどう分けるかなどをこんな風に図に起こして 設計 するのが当たり前ですが、
スクリーンショット 2021-05-02 5.33.19.png
今回は超絶シンプルなメモアプリなので設計なんて大そうな作業は不要です。

ちなみにテーブル、カラムなど超基本のデータベース用語ですが、カラムが列(項目)で、テーブルがそれをまとめる表のイメージです。
スクリーンショット 2021-05-02 5.14.59.png

データベース構築はこれで完了です。

####Step3:ページを用意
続いてクライアント側の画面であるページを作っていきます。
Node.jsではテンプレートエンジンというクライアント側の画面が簡単に作成できるパッケージがあります。Express-Generatorで既にejsというテンプレートエンジンがインストール済みなので、これを使ってページを作っていきます。

今回必要なページは4つです。views配下にmemoという名前でフォルダを作り、
メモ一覧表示ページ: index.ejs
新規メモ追加ページ: add.ejs
メモ編集ページ: edit.ejs
メモ削除ページ: delete.ejs
を作成してください、中身のコードは以下になります。

index.ejs

<!DOCTYPE html>
<html>
  <head>
    <title><%= title %></title>
  </head>
  <body>
    <h3><%= title %> <a href="/memo/add">追加</a></h3>
    <div>
      <table>
      <% for(var i in content) { %>
        <tr>
          <% var obj = content[i]; %>
          <td><%= obj.text %></td>
          <td><a href="/memo/edit?id=<%= obj.id %>">更新</a></td>
          <td><a href="/memo/delete?id=<%= obj.id %>">削除</a></td>
        </tr>
      <% } %>
      </table>
    </div>
  </body>
</html>

add.ejs(index.ejsとbodyタグ以外は同じ)

  <body>
    <h3><%= title %></h3>
    <p><%= content %></p>
    <div>
      <form action="/memo/add" method="post">
        <p>メモ内容:<input type="text" name="text"></p>  
        <input type="submit" value="追加">
      </form>
    </div>
  </body>

edit.ejs(index.ejsとbodyタグ以外は同じ)

  <body>
    <h3><%= title %></h3>
    <p><%= content %></p>
    <div>
      <form action="/memo/edit" method="post">
        <p>メモ内容:<input type="text" name="text" value="<%= memoData.text %>"></p>
        <input type="hidden" name="id" value="<%= memoData.id %>">
        <p><input type="submit" value="更新"></p>
      </form>
    </div>
  </body>

delete.ejs(index.ejsとbodyタグ以外は同じ)

  <body>
    <h3><%= title %></h3>
    <p><%= content %></p>
    <div>
      <p>メモ内容:<%= memoData.text %></p>
      <form action="/memo/delete" method="post">
        <input type="hidden" name="id" value="<%= memoData.id %>">
        <p><input type="submit" value="削除"></p>
      </form>
    </div>
  </body>

見ての通り基本はHTMLファイルで、値を受け取ってそれを表示したり、値を送ったりしているだけです。
title, content, memoDataという名前で値を送る処理はroutes(サーバー側)から行ってます。

####Step4:CRUD処理を実装
最後に肝心のCRUD処理を実装していきます。

routes配下にmemo.jsというファイルを作り、以下の処理を書いていきます。
各所にコメントを入れてあります。

var express = require('express');
var router = express.Router();

var sqlite3 = require('sqlite3');

//データベースオブジェクトの取得
const db = new sqlite3.Database('memo_data.sqlite3');

router.get('/', function(req, res, next) {
    db.serialize(() => {
        //SQL文, memosテーブルから全てのレコードを取得する(* は全て)
        db.all("select * from memos", (err, rows) => {
            if (!err) {
                const data = {
                    title: 'To Do メモ 一覧表示',
                    content: rows //DataBaseから返された全レコードがrowsに配列で入ります
                }
                //viewファイルのmemo/indexにdataオブジェクトが渡されます
                //res.render(テンプレートファイル名, { 渡す値をオブジェクトで }) → テンプレートファイルを描画する
                res.render('memo/index', data);
            }
        })
    })
});

router.get('/add', function(req, res, next) {
    const data = {
        title: '追加',
        content: '新しいデータを入力してください'
    }
    res.render('memo/add', data);
});

router.post('/add', function(req, res, next) {
    const tx = req.body.text;
    //SQL文, DataBaseのレコード作成
    db.run('insert into memos (text) values (?)', tx)
    //res.redirect() 引数に指定したアドレスにリダイレクト
    res.redirect('/memo');
});

router.get('/edit', function(req, res, next) {
    const id = req.query.id;
    db.serialize(() => {
        const q = "select * from memos where id = ?";
        db.get(q, [id], (err, row) => {
            if (!err) {
                const data = {
                    title: '更新',
                    content: 'id = ' + id + 'のレコードを更新',
                    memoData: row
                }
                res.render('memo/edit', data);
            }
        })
    })
});

router.post('/edit', function(req, res, next) {
    //POST送信された値はreq.body内にまとまられている
    const id = req.body.id;
    const tx = req.body.text;
    const q = "update memos set text = ? where id = ?";
    db.run(q, tx, id);
    res.redirect('/memo');
});


router.get('/delete', function(req, res, next) {
    const id = req.query.id;
    db.serialize(() => {
        const q = "select * from memos where id = ?";
        db.get(q, [id], (err, row) => {
            if (!err) {
                const data = {
                    title: '削除',
                    content: 'id = ' + id + 'のメモを削除しますか?',
                    memoData: row
                }
                res.render('memo/delete', data);
            }
        })
    })
});

router.post('/delete', function(req, res, next) {
    const id = req.body.id;
    const q = "delete from memos where id = ?";
    db.run(q, id);
    res.redirect('/memo');
});

module.exports = router;

そして、app.jsに以下を追記してください

var memoRouter = require('./routes/memo');

app.use('/memo', memoRouter);

ここまでできたらnpm startを実行して、http://localhost:3000/memoを開いてください。
スクリーンショット 2021-05-03 18.10.57.png

最初に登録したダミーデータが表示されていれば一覧表示はうまくいってます。
追加、更新、削除も機能していればバッチリです。

スクリーンショット 2021-05-02 22.09.39.png

スクリーンショット 2021-05-02 22.09.21.png

スクリーンショット 2021-05-02 22.09.30.png

##なぜサーバーサイドが必要?
ローカルストレージ機能を使えば一時保存できるので、簡易的なメモアプリであればフロントだけで完結できます。しかし、大きすぎるデータや、DataBaseにきちんと保存するのであればサーバーサイドが必要になります。(ブラウザからDataBaseにアクセスできないから)

それ以外の理由ではフロントではできない複雑な処理などをサーバー側でやってもらうと言う理由があります。

##まとめ
テーブル1個のこんなシンプルなアプリなんて現場ではまずあり得ないと思います(せめて複数テーブルの結合innerjoin, outerjoinくらいはやっておくべきでしょうか)が、Node.js、サーバーサイドに徐々に慣れてきました。

次はREST APIに関しての記事を書こうと思います。

15
14
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?