Express4 で フラッシュメッセージを利用する方法のメモ

[Node.js + express で express-session でセッション管理する方法](http://qiita.com/MahoTakara/items/05d1c9fd1a1ee14dc01c)について、Express 4.x で、ログイン失敗時に、フラッシュ・メッセージを表示する方法についても備忘録です。

実現したい事は、ログインに失敗した場合、１回のリクエストのライフサイクルの間だけ、**エラーメッセージ** を表示する事です。
![スクリーンショット 2017-05-15 21.49.44.png](https://qiita-image-store.s3.amazonaws.com/0/42829/294d42b7-b65e-1f19-0e35-d651a9691abe.png)

## コードの修正箇所
以下のExpress4.x アプリケーション・ジェネレータの出力に、セッション管理とフラッシュメッセージを追加についての記録です。

~~~
$ express --css stylus myapp1
~~~
app.js のコードに、以下のコードを追加します。

~~~file:myapp1/app.js
<中略>
var favicon = require('serve-favicon');
var logger = require('morgan');

//セッション管理、ログイン失敗メッセージに必要なコード 追加部分ここから
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var session = require('express-session');
var flash = require('express-flash');
var handlebars = require('express-handlebars');
var sessionStore = new session.MemoryStore;
// 追加部分 ここまで

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

var app = express();
<中略>
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));

//　セッション情報設定 追加部分ここから                                                                                               
app.use(cookieParser('secret'));
app.use(session({
    cookie: { maxAge: 60000 },
    store: sessionStore,
    saveUninitialized: true,
    resave: 'true',
    secret: 'secret'
}));
app.use(flash());
// 追加部分 ここまで

// CSS プリプロセッサ設定                                                                                            
app.use(require('stylus').middleware(path.join(__dirname, 'public')));
app.use(express.static(path.join(__dirname, 'public')));
<中略>

//  追加部分 ここから
app.use(require('./login'));  // ログイン　ミドルウェア                                                              
app.use('/', routes);         // ログイン画面、トップ画面送出                                                        
app.use('/logout', routes);　 // ログアウト処理　POSTで対応                                                          
app.use('/users', users);     // コンテンツ表示                                                                      
// 追加部分 ここまで、

// catch 404 and forward to error handler                                                                            
// ログインしてない場合は、login.js で捕捉して、ログインページへ飛ばす                                               
app.use(function(req, res, next) {
  var err = new Error('Not Found');
  err.status = 404;
  next(err);
});

// 以下１行追加
app.use('/:page', routes);　　// デフォルト設定 　ルート以下全て、routesへルーティング
~~~

login.js の ログイン管理のミドルウェアに変更を加えます。 ログインに失敗した時に、ログインフォームに表示するフラッシュメッセージをセットします。 var login から始まる行に、判定条件 && req.url != '/logout' を追加します。

~~~file:myapp1/login.js
File Edit Options Buffers Tools Javascript Help                                                                      
var users = { 'tkr': 'password' };  // ユーザーパスワード                                                            

module.exports = function(req, res, next) {

    var method = req.method.toLowerCase();
    var user = req.body;
    var logout = (method === 'post' && req.url === '/logout');
    var login = (method === 'post' && user && req.url != '/logout');  // 条件変更

    // ログアウト                                                                                                    
    if (logout) {
        delete req.session.user;
    }

    // ログイン                                                                                                      
    if (login) {
	Object.keys(users).forEach(function(name) {
            if (user.name === name && user.pwd === users[name]) {
		req.session.user = {
                    name: user.name,
                    pwd: user.pwd
		};
            // 追加部分 ここから
            } else {
		req.flash('success', 'ログイン失敗、ユーザー名またはパスワードが誤りです。');
            }
            // 追加部分 ここまで
	});
    }

    // セッションが無ければ ログイン画面へ                                                                           
    if (!req.session.user) {req.url = '/'}

    next();
}
~~~
ルーター設定ファイルの res.render から始まる行で、JSONの要素 expressFlash: req.flash('success') を追加します。 これで画面VIEWファイルに、フラッシュ・メッセージが伝達され表示可能となります。

~~~file:myapp1/routes/index.js
var express = require('express');
var router = express.Router();

function render(req, res, next) {
    res.render('index', { title: 'Express', user: req.session.user, expressFlash: req.flash('success') });
}

router.get('/', function(req, res, next) {
    render(req, res, next);
});

router.post('/', function(req, res, next) {
    render(req, res, next);
});

module.exports = router;
~~~
JADEのファイルの最後の部分に、２行追加します。 これで、#{ expressFlash } の部分がメッセージに置き換わります。

~~~file:myapp1/views/login.jade部分
<中略>
       p
         label(for='pwd') パスワード：
         input(type='password', name='pwd')
       input(type='submit')
   // 以下２行を追加
   if expressFlash.length > 0
       p <strong>エラーメッセージ:</strong> #{ expressFlash }
~~~

## パッケージ追加
以下、Express コマンドで作成される package.json に加えて ３つのモジュールをインストールします。

~~~
$ npm install express-session --save
$ npm install express-flash --save
$ npm install express-handlebars --save
~~~
生成された package.json は、以下の様になります。

~~~file:package.json
$ cat package.json 
{
  "name": "myapp1",
  "version": "0.0.0",
  "private": true,
  "scripts": {
    "start": "node ./bin/www"
  },
  "dependencies": {
    "body-parser": "~1.15.1",
    "cookie-parser": "~1.4.3",
    "debug": "~2.2.0",
    "express": "~4.13.4",
    "express-flash": "0.0.2",
    "express-handlebars": "^3.0.0",
    "express-session": "^1.15.2",
    "jade": "~1.11.0",
    "morgan": "~1.7.0",
    "serve-favicon": "~2.3.0",
    "stylus": "0.54.5"
  }
}
~~~

## アプリ実行
以下のコマンドを実行して、アプリをスタートします。

~~~
$ pwd
myapp1
$ npm start
~~~

以上です。

# 参考資料

[1] npm express-flash https://www.npmjs.com/package/express-flash