18
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?

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

Last updated at Posted at 2021-05-02

本記事ではNode.jsExpressSQLiteを使って、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の構築です。

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

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

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

4. カラムを作る
カラムは以下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個のこんなシンプルなアプリなんて現場ではまずあり得ないですが、Node.js、サーバーサイドに入門には丁度いいと思います。

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

18
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
18
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?