ExpressのMiddlewareを自作してみる

http://expressjs.com/guide/using-middleware.html
expressのmiddlewareに興味がわいたので自作してみます。ですのでまず上記サイトを読むことにしました。
#結論
`app.use(function (req, res, next) {})`
もしくは
`app.use router` か　`app.use routers`
以下は上記サイトを自分なりに解釈した駄文になります。

#Middlewareとは
* request, response, next を受け取るfunction
* どんなコードでもいい
* requestとresponseを変更してよい
* リクエストを終了してもいい
* nextを呼びリクエストを続行してもいい
* リクエストを終了しない場合はnextを必ず呼ぶこと
* オプションでmiddlewareの対象となるパスを指定できる
* アプリケーションレベル、ルーターレベル、エラーハンドリング、ビルドイン、サードパティの５種類がある

#Application level middleware
* `using app.use()`と`app.VERB()`によりexpressインスタンスに紐づけされる。　VERBはgetとか。

全リクエストに紐づけされるmiddlewareの例

```
// a middleware with no mount path; gets executed for every request to the app
app.use(function (req, res, next) {
  console.log('Time:', Date.now());
  next();
});
```

紐づけるパスを限定する例

```
// a middleware mounted on /user/:id; will be executed for any type of HTTP request to /user/:id
app.use('/user/:id', function (req, res, next) {
  console.log('Request Type:', req.method);
  next();
});
// a route and its handler function (middleware system) which handles GET requests to /user/:id
app.get('/user/:id', function (req, res, next) {
  res.send('USER');
});
```

expressで作成したapp.jsの`app.use('/', routes);`の前にとりあえず両方を記述してログを見てみました。
/にアクセスした場合

```
Time: 1426909974303
```

/user/3にアクセスした場合

```
Time: 1426909953812
Request Type: GET
```

できてますね。`app.use('/', routes);`より前に記述しないと/にアクセスしても実行されないので気を付けて。

またパスに対してmiddlewareを複数登録できるようです。'/user/:id'のmiddlewareを以下のように変更します。

```
app.use('/user/:id', function(req, res, next) {
  console.log('Request URL:', req.originalUrl);
  next();
}, function (req, res, next) {
  console.log('Request Type:', req.method);
  next();
});
```

/user/3にアクセス

```
Time: 1426910635722
Request URL: /user/3
Request Type: GET
```

できましたね。あと別にバラバラに書いても問題ないみたいです。

```
app.use('/user/:id', function(req, res, next) {
  console.log('Request URL:', req.originalUrl);
  next();
});

app.use('/user/:id', function (req, res, next) {
  console.log('Request Type:', req.method);
  next();
});
```

注意点は途中でsendするmiddlewareなどリクエストを終了するmiddlewareがあると以降のmiddlewareは実行されない点です。

```

app.use('/user/:id', function(req, res, next) {
  console.log('Request URL:', req.originalUrl);
  next();
});

app.get('/user/:id', function (req, res, next) {
  res.send('USER');
});

//実行されない
app.use('/user/:id', function (req, res, next) {
  console.log('Request Type:', req.method);
  next();
});
```

/user/3にアクセス

```
Time: 1426910635722
Request URL: /user/3
```

連続して書いた場合、middlewareはシリーズとして扱われます。この利点はシリーズの途中で実行を中止し、次の他のmiddlewareへ移行できる点です。ただしgetなどのVERBメソッドを使用する必要があります。

```
app.get('/user/:id', 
  function(req, res, next) {
    console.log('One in Middleware Series:');
    next();
  },
  function(req, res, next) {
    console.log('Two in Middleware Series::');
    next('route');
  },
  function(req, res, next) {
    console.log('Three but never run');
    next();
  }
);

app.get('/user/:id', function (req, res, next) {
  console.log('Another Middleware:');
  next();
});

app.get('/user/:id', function (req, res, next) {
  res.send('USER');
});
```

実行結果

```
One in Middleware Series:
Two in Middleware Series::
Another Middleware:
```
#Router level middleware
express.Router()に紐づけされる以外はアプリケーションレベルと同じようです。

#Error-handling middleware
他と異なり４つの引数を持ちます。
`(err, req, res, next)`

試しにエラーを強制的に発生させてみます。

```
app.get('/user/:id', function (req, res, next) {
  throw new Error("err")
  res.send('USER');
});

app.use(function(err, req, res, next) {
  console.error(err.stack);
  res.status(500).send('Something broke!');
});
```

ブラウザ画面　`Something broke!`
コンソール

```
Error: err
    at app.use.err.status (/home/ubuntu/workspace/express/demo/app.js:54:9)
    at Layer.handle [as handle_request] (/home/ubuntu/workspace/express/demo/node_modules/express
...
```

できましたね。
詳しくはhttp://expressjs.com/guide/error-handling.html を参照とのことです。

#Built-in middleware
4系からsessionなどの過去に組み込まれていたmiddlewareは全て分離したそうです。ただし静的ファイルを扱う `express.static`だけは組み込まれているようです。

#Third-party middleware
Expressは最小構成だから必要ならサードパティのミドルウェアで機能追加してねみたいな話でした。

#まとめ
`app.use(function (req, res, next) {})`できればmiddleware作れる。最後まで読む必要なかったな！！
実際つくってみるとRouter返したほうがやりやすいかも。用途によるかな？