Home

Express Memo

■Node.js基本編 Express+SQLiteで超定番のToDoメモアプリを作る
kokaki@skynew:~$ mkdir www/express
kokaki@skynew:~$ cd www/express/
kokaki@skynew:~/www/express$ sudo apt install -y npm
    [sudo] password for kokaki:
    Reading package lists... Done
    Building dependency tree... Done
    Reading state information... Done
    npm is already the newest version (9.2.0~ds1-2).
    0 upgraded, 0 newly installed, 0 to remove and 2 not upgraded.
    2 not fully installed or removed.
    After this operation, 0 B of additional disk space will be used.
    Setting up pgadmin4-desktop (8.14) ...
    Load apparmor pgAdmin profile...
    Cache read/write disabled: interface file missing. (Kernel needs AppArmor 2.4 compatibility patch.)
    Warning: unable to find a suitable fs in /proc/mounts, is it mounted?
    Use --subdomainfs to override.
    dpkg: error processing package pgadmin4-desktop (--configure):
    installed pgadmin4-desktop package post-installation script subprocess returned error exit status 1
    dpkg: dependency problems prevent configuration of pgadmin4:
    pgadmin4 depends on pgadmin4-desktop (= 8.14); however:
    Package pgadmin4-desktop is not configured yet.

    dpkg: error processing package pgadmin4 (--configure):
    dependency problems - leaving unconfigured
    No apport report written because the error message indicates its a followup error from a previous failure.
    Errors were encountered while processing:
    pgadmin4-desktop
    pgadmin4
    E: Sub-process /usr/bin/dpkg returned an error code (1)
kokaki@skynew:~/www/express$ sudo npm install -g express-generator
    npm WARN deprecated mkdirp@0.5.1: Legacy versions of mkdirp are no longer supported.
    Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)

    added 10 packages in 878ms
kokaki@skynew:~/www/express$ express -e todo-app
    warning: option `--ejs' has been renamed to `--view=ejs'


    create : todo-app/
    create : todo-app/public/
    create : todo-app/public/javascripts/
    create : todo-app/public/images/
    create : todo-app/public/stylesheets/
    create : todo-app/public/stylesheets/style.css
    create : todo-app/routes/
    create : todo-app/routes/index.js
    create : todo-app/routes/users.js
    create : todo-app/views/
    create : todo-app/views/error.ejs
    create : todo-app/views/index.ejs
    create : todo-app/app.js
    create : todo-app/package.json
    create : todo-app/bin/
    create : todo-app/bin/www

    change directory:
        $ cd todo-app

    install dependencies:
        $ npm install

    run the app:
        $ DEBUG=todo-app:* npm start
kokaki@skynew:~/www/express$ cd todo-app/
kokaki@skynew:~/www/express/todo-app$ npm install
    added 54 packages, and audited 55 packages in 3s

    8 vulnerabilities (3 low, 4 high, 1 critical)

    To address all issues (including breaking changes), run:
    npm audit fix --force

    Run `npm audit` for details.
kokaki@skynew:~/www/express/todo-app$ npm install sqlite3
    npm WARN deprecated inflight@1.0.6: This module is not supported, and leaks memory. Do not use it. 
    Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, 
    which is much more comprehensive and powerful.
    npm WARN deprecated rimraf@3.0.2: Rimraf versions prior to v4 are no longer supported
    npm WARN deprecated npmlog@6.0.2: This package is no longer supported.
    npm WARN deprecated glob@7.2.3: Glob versions prior to v9 are no longer supported
    npm WARN deprecated @npmcli/move-file@1.1.2: This functionality has been moved to @npmcli/fs
    npm WARN deprecated are-we-there-yet@3.0.1: This package is no longer supported.
    npm WARN deprecated gauge@4.0.4: This package is no longer supported.

    added 127 packages, and audited 182 packages in 8s

    12 packages are looking for funding
    run `npm fund` for details

    8 vulnerabilities (3 low, 4 high, 1 critical)

    To address all issues (including breaking changes), run:
    npm audit fix --force

    Run `npm audit` for details.
kokaki@skynew:~/www/express/todo-app$ DEBUG=todo-app:* npm start
    > todo-app@0.0.0 start
    > node ./bin/www

    todo-app:server Listening on port 3000 +0ms
    GET / 200 31.754 ms - 207
    GET /stylesheets/style.css 200 9.417 ms - 111
    GET /favicon.ico 404 3.787 ms - 1033
    ^C
http://localhost:3000/
Express アプリ

kokaki@skynew:~/www/express/todo-app$ npm fund
    todo-app@0.0.0
    ├── https://github.com/sponsors/ljharb
    │   └── minimist@1.2.8
    ├─┬ https://github.com/sponsors/feross
    │ │ └── simple-get@4.0.1, simple-concat@1.0.1, buffer@5.7.1, base64-js@1.5.1, ieee754@1.2.1, safe-buffer@5.2.1
    │ └── https://github.com/sponsors/sindresorhus
    │     └── decompress-response@6.0.0, mimic-response@3.1.0, p-map@4.0.0
    └── https://github.com/sponsors/isaacs
        └── glob@7.2.3, rimraf@3.0.2
kokaki@skynew:~/www/express/todo-app$ npm audit
    # npm audit report

    body-parser  <=1.20.2
    Severity: high
    body-parser vulnerable to denial of service when url encoding is enabled - https://github.com/advisories/GHSA-qwcr-r2fm-qrc7
    Depends on vulnerable versions of qs
    fix available via `npm audit fix --force`
    Will install express@4.21.2, which is outside the stated dependency range
    node_modules/body-parser
    express  <=4.21.1 || 5.0.0-alpha.1 - 5.0.0
    Depends on vulnerable versions of body-parser
    Depends on vulnerable versions of cookie
    Depends on vulnerable versions of path-to-regexp
    Depends on vulnerable versions of qs
    Depends on vulnerable versions of send
    Depends on vulnerable versions of serve-static
    node_modules/express

    cookie  <0.7.0
    cookie accepts cookie name, path, and domain with out of bounds characters - https://github.com/advisories/GHSA-pxg6-pf52-xh8x
    fix available via `npm audit fix --force`
    Will install express@4.21.2, which is outside the stated dependency range
    node_modules/express/node_modules/cookie

    ejs  <=3.1.9
    Severity: critical
    ejs template injection vulnerability - https://github.com/advisories/GHSA-phwq-j96m-2c2q
    ejs lacks certain pollution protection - https://github.com/advisories/GHSA-ghr5-ch3p-vcr6
    fix available via `npm audit fix --force`
    Will install ejs@3.1.10, which is a breaking change
    node_modules/ejs


    path-to-regexp  <=0.1.11
    Severity: high
    path-to-regexp outputs backtracking regular expressions - https://github.com/advisories/GHSA-9wv6-86v2-598j
    Unpatched `path-to-regexp` ReDoS in 0.1.x - https://github.com/advisories/GHSA-rhx6-c78j-4q9w
    fix available via `npm audit fix --force`
    Will install express@4.21.2, which is outside the stated dependency range
    node_modules/path-to-regexp

    qs  6.5.0 - 6.5.2
    Severity: high
    qs vulnerable to Prototype Pollution - https://github.com/advisories/GHSA-hrpp-h998-j3pp
    fix available via `npm audit fix --force`
    Will install express@4.21.2, which is outside the stated dependency range
    node_modules/qs

    send  <0.19.0
    send vulnerable to template injection that can lead to XSS - https://github.com/advisories/GHSA-m6fv-jmcg-4jfg
    fix available via `npm audit fix --force`
    Will install express@4.21.2, which is outside the stated dependency range
    node_modules/send
    serve-static  <=1.16.0
    Depends on vulnerable versions of send
    node_modules/serve-static


    8 vulnerabilities (3 low, 4 high, 1 critical)

    To address all issues (including breaking changes), run:
    npm audit fix --force
kokaki@skynew:~/www/express/todo-app$ npm audit fix --force
    npm WARN using --force Recommended protections disabled.
    npm WARN audit Updating ejs to 3.1.10, which is a SemVer major change.
    npm WARN audit Updating express to 4.21.2, which is outside your stated dependency range.

    added 59 packages, changed 17 packages, and audited 241 packages in 3s

    27 packages are looking for funding
    run `npm fund` for details

    found 0 vulnerabilities
kokaki@skynew:~/www/express/todo-app$ sqlite3 memo_data.sqlite3
    SQLite version 3.45.1 2024-01-30 16:01:20
    Enter ".help" for usage hints.
    sqlite> CREATE TABLE "memos" (
               "id" INTEGER NOT NULL UNIQUE,
               "text" TEXT NOT NULL,
               PRIMARY KEY("id" AUTOINCREMENT));
    sqlite> .q
kokaki@skynew:~/www/express/todo-app$ mkdir views/memo
kokaki@skynew:~/www/express/todo-app$ touch views/memo/index.ejs
kokaki@skynew:~/www/express/todo-app$ touch views/memo/add.ejs
kokaki@skynew:~/www/express/todo-app$ touch views/memo/edit.ejs
kokaki@skynew:~/www/express/todo-app$ touch views/memo/delete.ejs
kokaki@skynew:~/www/express/todo-app$ touch routes/memo.js
kokaki@skynew:~/www/express/todo-app$ vi views/memo/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>
kokaki@skynew:~/www/express/todo-app$ vi views/memo/add.ejs
    <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>
kokaki@skynew:~/www/express/todo-app$ vi views/memo/edit.ejs
    <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>
kokaki@skynew:~/www/express/todo-app$ vi views/memo/delete.ejs
    <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>
kokaki@skynew:~/www/express/todo-app$ vi routes/memo.js
    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;
kokaki@skynew:~/www/express/todo-app$ vi app.js
    var createError = require('http-errors');
    var express = require('express');
    var path = require('path');
    var cookieParser = require('cookie-parser');
    var logger = require('morgan');

    var indexRouter = require('./routes/index');
    var usersRouter = require('./routes/users');

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

    var app = express();

    // view engine setup
    app.set('views', path.join(__dirname, 'views'));
    app.set('view engine', 'ejs');

    app.use(logger('dev'));
    app.use(express.json());
    app.use(express.urlencoded({ extended: false }));
    app.use(cookieParser());
    app.use(express.static(path.join(__dirname, 'public')));

    app.use('/', indexRouter);
    app.use('/users', usersRouter);

    app.use('/memo', memoRouter); // 追加★

    // catch 404 and forward to error handler
    app.use(function(req, res, next) {
    next(createError(404));
    });
    :
    :
    :
kokaki@skynew:~/www/express/todo-app$ npm start
    > todo-app@0.0.0 start
    > node ./bin/www

    GET /memo 200 25.695 ms - 242
    GET /memo/add 200 4.533 ms - 287
    POST /memo/add 302 35.403 ms - 34
    GET /memo 200 16.230 ms - 437
    GET /memo/edit?id=1 200 6.391 ms - 353
    POST /memo/edit 302 2.570 ms - 34
    GET /memo 200 10.745 ms - 449
    GET /memo/add 200 2.430 ms - 287
    POST /memo/add 302 1.361 ms - 34
    GET /memo 200 8.624 ms - 669
    GET /memo/delete?id=2 200 4.634 ms - 347
    POST /memo/delete 302 44.658 ms - 34
    GET /memo 200 9.540 ms - 449
    ^C
http://localhost:3000/memo
Express Memo アプリ

■Apache2からExpressにアクセスする方法
kokaki@skynew:~/www/express/todo-app$ sudo vi /etc/apache2/sites-available/express.conf
[sudo] password for kokaki:
    
    ProxyPass /memo http://localhost:3000/memo
    ProxyPassReverse /memo http://localhost:3000/memo
kokaki@skynew:~/www/express/todo-app$ sudo a2ensite express
    Enabling site express.
    To activate the new configuration, you need to run:
      systemctl reload apache2
kokaki@skynew:~/www/express/todo-app$ sudo a2enmod proxy
    Module proxy already enabled
kokaki@skynew:~/www/express/todo-app$ sudo a2enmod proxy_http
    Considering dependency proxy for proxy_http:
    Module proxy already enabled
    Enabling module proxy_http.
    To activate the new configuration, you need to run:
      systemctl restart apache2
kokaki@skynew:~/www/express/todo-app$ sudo systemctl restart apache2

http://localhost/memo
Express Memo アプリ

Home

2025 kokaki.jp, Office.