【node.js】expressでapiサーバーを実装するときに最低限必要そうなことをまとめておく

はじめに

socket.ioを使って簡単なチャットサーバーを作ろうとしました

当初、socket.ioを使わないapiの実装はphpで、socket.ioの部分だけnode.jsで・・・と考えていたのですが
どうせならapiの部分もnode.jsで作った方がいいのかなと思ってちょっと調べことをメモ

ほしい機能
・getまたはpostリクエストを受け取ってjsonを返す
mysqlを使う
アクセスログ、エラーログ、アプリのログを出力
・定数をどこかにまとめる
・サーバーが落ちた時に再起動するようにしたい

使った方が便利そうなもの
・バリデーションのライブラリ
・Promiseを使ってコールバック地獄にならないように

とりあえずはこんなところだろうか

getまたはpostリクエストを受け取る

ここで必要そうなことはアクセスされるurlによって処理を振り分けることとgetとpostのパラメータを受け取ること

urlによって処理を振り分ける

app.js

var app = require("express")();
var http = require("http").Server(app);

// loginにgetでアクセスされた時の処理
app.get("/login", function(req, res) {
});

// registerにpostでアクセスされた時の処理
app.post("/register", function(req, res) {
});

http.listen(3000, function() {
    console.log("listening on *:3000");
});
getパラメータとpostパラメータを受け取る

getパラメータ

app.get("/login", function(req, res) {
    // req.query.email
    // req.query.password
});

postパラメータ

// postを使うにはコレが必要
var bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());

app.post("/register", function(req, res) {
    // req.body.email
    // req.body.password
});

jsonを返す

これは簡単で以下

app.get("/login", function(req, res) {
    if (req.query.email && req.query.password) {
        // ログインのチェックなど
        if (okの場合) {
            req.json({ "status" => "ok" });
        } else {
            req.json({ "status" => "ng", "message" => "emailまたはパスワードが正しくありません" });
        }
    } else {
        req.json({ "status" => "ng", "message" => "emailまたはパスワードが入力されていません" });
    }
});

mysqlを使う

mongodbを使うことが多いようだけど今回は慣れてるmysqlを使う

【node.js】expressにてmysqlを使う方法メモ - とりあえずphpとか
が、ちょっと長くなったのでこっちにまとめた

アクセスログ、エラーログ、アプリのログ出力

実際に運用していくとなったらログ処理は必須と思う
expressの標準でmorganというのがあるようだけど、調べているとlog4jsというのを使ってる人が多そうだったので今回はこれを使う。

log.js(ログ出力用のモジュール)

var log4js = require('log4js');

// 設定
log4js.configure({
        "appenders": [{
                "category": "access",
                "type": "dateFile",
                "filename": "/var/www/html/example.com/log/access.log",
                "pattern": "-yyyy-MM-dd"
            }, {
                "category": "app",
                "type": "dateFile",
                "filename": "/var/www/html/example.com/log/system.log",
                "pattern": "-yyyy-MM-dd"
            }, {
                "category": "error",
                "type": "dateFile",
                "filename": "/var/www/html/example.com/log/error.log",
                "pattern": "-yyyy-MM-dd"
            }, {
                "type": "console"
            }],
});

var logApp = log4js.getLogger("app");
var logAccess = log4js.getLogger("access");
var logError = log4js.getLogger("error");

// アクセスログ
exports.access = log4js.connectLogger(log4js.getLogger("access"), {
    level: log4js.levels.INFO
});

// エラーログ
exports.app = function(message) {
    logApp.info(message);
};

// アプリごとのログ
exports.error = function(message) {
    logError.info(message);
};

app.js(実際にログ出力)

var log = require('./log.js');

// アクセスログを使う設定
app.use(log.access);

// アプリのログ出力
app.get("/login", function(req, res) {
    log.app(req.query);
});

// エラーログ出力
app.use(function(err, req, res, next) {
    log.error(err);
});

出力例

[2016-06-20 11:36:59.837] [INFO] access - ::ffff:123.456.789.012 - - "POST /register HTTP/1.1" 200 63 "" "curl/7.43.0" # アクセスログ
[2016-06-20 11:38:12.485] [INFO] app - MySQLへ接続成功 # アプリのログ

定数をまとめる

node-configというのを使った

config/default.json(設定ファイル)

{
    "db": {
        "host": "db_host",
        "user": "db_user",
        "password": "db_password",
        "database": "db_name"
    },

    "log": {
        "appenders": [{
             // ログのところに書いた内容とか
        }],
    }
}

mysqlへの接続情報やlogの出力設定などはここにまとめておくと良いと思う

app.js(設定を呼び出す)

var config = require("config");
// config.dbで呼び出し

サーバーが落ちた時に再起動したい

pm2というのを使ってみた。app.jsが落ちても再起動してくれる。
まだわからないけど、現時点ではこれでいこうかなと思ってます

使ってみたコマンドは以下

# サーバー起動
# --watchつけるとjsを編集すると自動で再起動してくれるので開発中はあった方が楽かと思う
./node_modules/pm2/bin/pm2 start app.js --watch

# コンソールに出力されるログの監視
./node_modules/pm2/bin/pm2 logs

# サーバーの動作状況確認
./node_modules/pm2/bin/pm2 list

┌──────────┬────┬──────┬───────┬────────┬─────────┬────────┬─────────────┬──────────┐
│ App name │ id │ mode │ pid   │ status │ restart │ uptime │ memory      │ watching │
├──────────┼────┼──────┼───────┼────────┼─────────┼────────┼─────────────┼──────────┤
│ app      │ 0  │ fork │ 23996 │ online │ 5       │ 19m    │ 43.254 MB   │  enabled │
└──────────┴────┴──────┴───────┴────────┴─────────┴────────┴─────────────┴──────────┘

# サーバー停止
./node_modules/pm2/bin/pm2 stop 0 # 0は上のidの数字
./node_modules/pm2/bin/pm2 delete all # 全て停止する場合

バリデーション

node-validatorというのがあった。便利そう

var validator = require('validator');

app.post("/register", function(req, res) {
    if (!validator.isEmail(req.body.email)) {
        // チェックエラー
    }
});

Promiseを使ってコールバック地獄にならないように

今度できたらメモする
ただ、コールバックが3つとかなり始めると見るのも嫌になりそうなので使った方が良さそう

【javascript】promiseの使い方メモ〜条件分岐とか - とりあえずphpとか
まとめてみた

さいごに

とりあえず実際にいじってみて上記なようなものがあれば、最低限いける気がしました
ただ、実際に仕事で使ってないので実際やってみたら全然たりなかったり問題点が見つかるのだろうな・・・

以上です