非同期処理

Promiseで非同期処理

mysql2でDB処理をするとき、mysql2/promise モジュールを利用して非同期処理をします。

const mysql = require('mysql2/promise');

SQLクエリの実行処理は非同期処理 async/await で実装します。

async () => {
    await SQL処理
}

ユーザ登録

Userモデル

Userクラスを作成しし、dbmysql2/promise モジュールを読み込みます。

const db = require('../lib/db');
const mysql = require('mysql2/promise');

class User {

}

module.exports = User
  • Userクラスはモジュール化します

ユーザ登録メソッド追加

ユーザ登録メソッド add() を追加し、非同期処理とします。

models/User.js
    add = async (post) => {

    }

MySQL接続

MySQLに接続し、SQL INSERTのテンプレートを用意します。

models/User.js
    add = async (post) => {
        const con = await mysql.createConnection(db.info);
        var sql = `INSERT INTO users SET ?;`;
        post.password = bcrypt.hashSync(post.password, 10);
    }

レコード挿入

「users」テーブルにレコード挿入するクエリを実行します。

models/User.js
    add = async (post) => {
        const con = await mysql.createConnection(db.info);
        var sql = `INSERT INTO users SET ?;`;
        var result;
        try {
            post.password = bcrypt.hashSync(post.password, 10);
            result = await con.query(sql, post);
        } catch (error) {

        } finally {
            await con.end();
        }
        return result;
    }
  • SQL実行エラーを「try-catch」で対応が必要です。

ユーザ登録フォーム

「RegistController.js」を作成し、Userモデルを読み込みます。

controllers/RegistController.js
const User = require('../models/User');

ユーザ登録入力画面

ユーザ登録入力画面のコントローラー、ビューを作成します。

controllers/RegistController.js
const User = require('../models/User');

exports.index = (req, res) => {
    var data = {}
    data.title = 'Regist'
    res.render('regist/index', data)
}
views/regist/index.ejs
<div class="col-6 m-auto">
  <form action="/regist/add" method="post">
    <div>
      <label class="mt-3 mb-3">名前</label>
      <input type="text" name="name" class="form-control">
    </div>

    <div>
      <label class="mt-3 mb-3">Email</label>
      <input type="text" name="email" class="form-control">
    </div>

    <div>
      <label class="mt-3 mb-3">パスワード</label>
      <input type="password" name="password" class="form-control">
    </div>

    <div class="text-center p-3">
      <button class="btn btn-primary">登録</button>
    </div>

    <div class="text-center p-3">
      <a href="/" class="btn btn-outline-primary">ホーム</a>
    </div>
  </form>
</div>

ユーザ登録処理

ユーザ登録メソッド追加

ユーザ登録メソッド add() を非同期処理で追加します。

controllers/RegistController.js
...

exports.index = (req, res) => {
    var data = {}
    data.title = 'Regist'
    res.render('regist/index', data)
}

//ユーザ登録メソッド
exports.add = async (req, res) => {

}

ユーザ登録処理

Userモデルを利用して、ユーザ登録処理を実行します。

controllers/RegistController.js
...

exports.add = async (req, res) => {
    //ユーザ登録処理
    const user = new User();
    await user.add(req.body);

    if (user.id) {
        req.session.authUser = user;
        res.redirect('/login');
    } else {
        res.redirect('/regist');
    }
}

リダイレクト

ユーザ登録ができたらログイン画面に、失敗したらユーザ登録画面にリダイレクトします。

controllers/RegistController.js
...

exports.add = async (req, res) => {
    const user = new User();
    var isSuccess = await user.add(req.body);
    if (isSuccess) {
        res.redirect('/login');
    } else {
        res.redirect('/regist');
    }
}

ルーティング

ユーザ登録のルーティングを追加します。

routes.js
const RegistController = require('./controllers/RegistController')

router.get('/regist', RegistController.index)
router.post('/regist/add', RegistController.add)

ユーザ登録確認

ユーザ登録画面にアクセスし、ユーザ登録できるか確認してみましょう。

演習

問題1

MySQLを利用してユーザ認証するように、ログインページを修正してみましょう。

ヒント

Userモデルに以下のような auth() メソッドを追加して認証します。 パスワードのハッシュ検証は、bcrypt.compareSync() を利用します。

models/User.js
const db = require('../lib/db');
const mysql = require('mysql2/promise');
const bcrypt = require('bcrypt');

class User {

    auth = async (email, password) => {
        const sql = 'SELECT * FROM users WHERE ?;';
        var post = { email: email };
        const con = await mysql.createConnection(db.info)
        var user;
        try {
            const [rows, fields] = await con.query(sql, post);
            user = rows[0];
        } catch (error) {

        } finally {
            await con.end();
        }
        if (user.id && bcrypt.compareSync(password, user.password)) {
            return user;
        }
        return;
    }

    add = async (post) => {
        var sql = `INSERT INTO users SET ?;`;
        const con = await mysql.createConnection(db.info)
        var result;
        try {
            post.password = bcrypt.hashSync(post.password, 10);
            result = await con.query(sql, post);
        } catch (error) {

        } finally {
            await con.end();
        }
        return result;
    }
}

module.exports = User

問題2

「ApiController」を作成して、ユーザ情報のJSONを表示してみましょう。