読者です 読者をやめる 読者になる 読者になる

【node.js】expressにてmysqlを使う方法メモ

はじめに

今回やりたかったことは以下
・expressからmysqlへクエリ実行
・ormは使わずsqlを直接実行したい
・dbの処理部分は共通化したい
・エラー処理も実装する

node-mysqlというライブラリを使いました

実装

ファイル構成
├── app.js
├── db.js # dbの共通処理はココにまとめる
├── controllers # コントローラはココに
│   ├── login.js 
│    ・・・
├── models # db処理はココに
│   ├── user.js
│    ・・・
共通処理を実装(db.js)

とりあえずselectとinsertのsqlを実行できるようにしておく
models以下の各クラスからこのクラスのメソッドを呼び出す

var mysql = require("mysql");
module.exports = {
    conn: null,

    // MySQLへ接続
    connect: function() {
        this.conn = mysql.createConnection({
            "host": "db_hostname",
            "user": "db_username",
            "password": "db_password",
            "database": "db_name"
        });
        this.conn.connect(function(err) {
            if (err) {
                // MySQLへ接続失敗
            } else {
                // MySQLへ接続成功
            }
        });
    },

    // 1件取得用メソッド
    getOne: function(query, params, callback) {
        this.conn.query(query, params, function(err, rows) {
            if (err) throw new Error();
            else callback(rows.length < 1 ? null : rows[0]);
        });
    },

    // 複数件取得用メソッド
    getAll: function(query, params, callback) {
        this.conn.query(query, params, function(err, rows) {
            if (err) throw new Error();
            else callback(rows);
        });
    },

    // insert実行用メソッド
    insert: function(table, data, callback) {
        this.conn.query("insert into " + table + " set ?", data, function(err, result, fields) {
            if (err) throw new Error();
            else callback(result.insertId);
        });
    }
}
modelの実装(models/user.js)

引数でcallbackを渡す形で実装しましたが、アプリが複雑になっていくとコールバック地獄なるものになるそうです・・・
なので、ここはPromiseを返すようにした方が良さそうだけど今回は話がそれるのでcallbackにしておきます

var db = require("../db.js");
module.exports = {

    // emailでusersテーブルを検索する
    getByEmail: function(email) {
        return new Promise(function(resolve, reject) {
            var query = "select * from users where email = ?";
            db.getOne(query, [email], function(row) {
                resolve(row);
            });
        });
    },

    // usersテーブルへinsertする
    register: function(data) {
        return new Promise(function(resolve, reject) {
            db.insert("users", data, function(id) {
                resolve(id);
            });
        });
    },
}
controllerの実装(controllers/login.js)
var express = require("express");
var user = require("../models/user.js");

module.exports = function() {
    var router = express.Router();
    router.get("/", function(req, res, next) {
        user.getByEmail(req.query.email)
            .then(function(row) {
                if (row) {
                    // 成功(jsonを返すなど)
                } else {
                    // 失敗(jsonを返すなど)
                }
            }
    });
    return router;
};

こんな感じでやりたいことはだいたい実装できました。
ただ、これだとdb.jsでエラーがあった場合に例外を投げてる箇所で以下のようなエラーで落ちてしまいました

/var/www/html/example.com/public/node_modules/mysql/lib/protocol/Parser.js:78
throw err; // Rethrow non-MySQL errors
^
Error
at Query._callback (/var/www/html/example.com/public/db.js:28:9)
at Query.Sequence.end (/var/www/html/example.com/public/node_modules/mysql/lib/protocol/sequences/Sequence.js:85:24)
at Query.ErrorPacket (/var/www/html/example.com/public/node_modules/mysql/lib/protocol/sequences/Query.js:94:8)
at Protocol._parsePacket (/var/www/html/example.com/public/node_modules/mysql/lib/protocol/Protocol.js:280:23)
at Parser.write (/var/www/html/example.com/public/node_modules/mysql/lib/protocol/Parser.js:74:12)
at Protocol.write (/var/www/html/example.com/public/node_modules/mysql/lib/protocol/Protocol.js:39:16)
at Socket.<anonymous> (/var/www/html/example.com/public/node_modules/mysql/lib/Connection.js:109:28)
at Socket.emit (events.js:107:17)
at readableAddChunk (_stream_readable.js:163:16)
at Socket.Readable.push (_stream_readable.js:126:10)

で、非同期処理の中で例外を投げるとエラーになるそうで、express-domain-middlewareを使うことで回避できました。

app.js

var domain = require('express-domain-middleware');
app.use(domain);

この2行を追加すればokでした

以上です