node初心者がexpress-generatorで吐き出されたapp.jsを読んでみる

[express-generator](http://expressjs.com/starter/generator.html)を使って、スケルトン作ってサンプル動かしたはいいものの、app.jsを見て、あー仕組み調べるのめんどくさって思った方のための記事です。nodeもexpressも初心者のiOSエンジニアが書いてますので、同じような状況の方にとって有益かと思います。

以下で、app.jsを上から順に読んで、必要なリファレンスへのリンクを載せたり、ざっくりこういうことしてるってことを書きます。

# app.js (express ver4.12.3の場合)
ソースはなにもしなければ、こんな感じになっていると思います。

```js:app.js
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');

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

var app = express();

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');

// uncomment after placing your favicon in /public
//app.use(favicon(__dirname + '/public/favicon.ico'));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

app.use('/', routes);
app.use('/users', users);

// catch 404 and forward to error handler
app.use(function(req, res, next) {
  var err = new Error('Not Found');
  err.status = 404;
  next(err);
});

// error handlers

// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
  app.use(function(err, req, res, next) {
    res.status(err.status || 500);
    res.render('error', {
      message: err.message,
      error: err
    });
  });
}

// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
  res.status(err.status || 500);
  res.render('error', {
    message: err.message,
    error: {}
  });
});


module.exports = app;
```

# 解説
上から順に見ていきます。

## 各種nodeモジュールをインスタンス化

```js:1~6行目
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
```

ここでまず知らないといけないのは、requireがどう動くか。

### requireに関して

requireで読み込めるモジュールは3タイプあるようです：

 1. **Core Modules** ... nodeのビルトインモジュール。nodeのソースの`lib/`配下にある。
 2. **File Modules** ... 1で見つからなければ、同名のファイル(.js/.json/.node)を読み込みます。
 3. **Loading from node_modules Folders** ... 1,2で見つからなければ、同ディレクトリに配置された`node_modules`から読み込みます

上記の中では、`require('path')`だけが1のタイプで、残りは3のタイプになります。

3のタイプのモジュールは、通常`package.json`の、dependenciesの部分に記載して、npm installしないと、node_moduleの中にソースが入ってきません。express-generatorでは自動で生成してくれているので省略できています。

ちなみに、1のタイプに関しては、nodebrewのバイナリでnodeを入れた人は、ソースないはずなんで、確認したい場合は[nodeのgitリポジトリ](https://github.com/joyent/node/tree/master/lib)をみるといいかもしれません。

※ 上記でrequireしているモジュール一覧

- [express](http://expressjs.com/) : nodejs用のwebアプリ作成フレームワーク
- [path](http://nodejs.jp/nodejs.org_ja/docs/v0.4/api/path.html) : ファイルパスを扱うユーティリティ
- [serve-favicon](https://github.com/expressjs/serve-favicon) : ファビコンを表示する
- [morgan](https://github.com/expressjs/morgan) : HTTPリクエストのログを吐き出す
- [cookie-parser](https://github.com/expressjs/cookie-parser) : クッキーをパースする
- [body-parser](https://github.com/expressjs/body-parser) : リクエストパラメータのパーサーを設定する

※ requireに関して、詳しくは[nodeの公式ドキュメント](http://nodejs.jp/nodejs.org_ja/api/modules.html)をご覧ください。

### ミドルウェアとは
expressフレームワークの中では、モジュールのことをミドルウェア(middleware)と呼んでいるようで、下記のように定義されています(意訳です)。

> ミドルウェアはリクエストオブジェクト(req)、レスポンスオブジェクト(res)、そして次のミドルウェアへのアクセスをもった一機能であり、下記のことができます：
 - 任意の処理を実行できる
 - リクエストやレスポンスオブジェクトに対して変更を加えられる
 - リクエスト-レスポンスサイクルを終了できる
 - 次のミドルウェアへ処理を渡すことができる


詳細に関しては、
 - [公式ページ](http://expressjs.com/guide/using-middleware.html)
 - [逆引きメモ：expressの使い方](http://qiita.com/morou/items/06cbe49f64d56d31b793#%E3%83%9F%E3%83%89%E3%83%AB%E3%82%A6%E3%82%A8%E3%82%A2%E3%82%92%E4%BD%BF%E3%81%86)
を参照するといいです。

## ルーティングモジュールを読み込む

```js:8-9行目
var routes = require('./routes/index');
var users = require('./routes/users');
```

このrequireは、上記タイプの2に相当します。'./' から始まる場合は、require() を呼んだファイルからの相対パスになります。では、index.jsの中を見てみましょう。

### index.js

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

/* GET home page. */
router.get('/', function(req, res, next) {
  res.render('index', { title: 'Express' });
});

module.exports = router;
```

ここでは、各pathに対するリクエストに対して任意の処理を行い、最終的にrouterオブジェクトをapp.jsに返しています。

### express.Router()とは
[公式リファレンス](http://expressjs.com/4x/api.html#router)によると、`var router = express.Router([options]);`という形で使い、ミドルウェアを実行したりルーティングを実行するメソッド群と考えて下さいとのこと。optionsには、大文字小文字の区別をするかとか、'/'の有無を区別するかとかを設定することができるようです。

### router.getとは
[router.get](http://expressjs.com/4x/api.html#router.METHOD)では、`router.METHOD(path, [callback, ...] callback)`という形で、特定のpathに来たリクエストに対しての処理を記述することができます。METHODで取れるのは、HTTPメソッドのそれと同じですが、小文字で書くルールです。

router.METHODは、後述するapp.use([path,] function [, function...])とほぼ同じような動きをするのですが、内部でnext()を呼ばなくても、**次のrouteへ処理を渡してくれる**点が異なります。

### res.renderとは
[res.render(view [, locals] [, callback])](http://expressjs.com/4x/api.html#res.render)という形で用い、viewパラメータにviewテンプレート名を指定し、localsパラメータには、連想配列を渡します (今回は、`{ title: 'Express' }`となっているので、indexテンプレートのtitle変数に'Express'が渡ります)。

### module.exportsとは
ルーティングを設定したrouterオブジェクトを返しています。詳細に関しては、[公式ドキュメント](http://nodejs.jp/nodejs.org_ja/api/modules.html#modules_module_exports)を参考にしてみてください。

## アプリケーションのインスタンスを作ります
ここで作成したインスタンスに後述するapp.getとかapp.setなどの処理を行っていきます。

```js:11行目
var app = express();
```

## app.set(name, value)
[app.set(name, value)](http://expressjs.com/4x/api.html#app.set)でアプリケーションの各種設定ができます。
`'name'`は、[app setting table](http://expressjs.com/4x/api.html#app.settings.table)で予め定義されているのでご注意ください。

ここでは、viewテンプレートが入ったフォルダと、viewテンプレートエンジンを設定しています。

```js:14-15行目
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
```

## app.use([path,] function [, function...])
[app.use](http://expressjs.com/4x/api.html#app.use)を使って、指定のpathにきたリクエストに対して、処理を記述できます。

が、app.use()のパラメータにミドルウェアがかんでいる場合は、パラメータが必ずしも`[path,] function [, function...]`になるとは限りません。ミドルウェアの内部に処理が隠蔽されているためです。また、先述のrouterの部分で、next()を呼ばないといけないと書きましたが、ミドルウェアの場合はそれも内部で任意に処理されているので、注意が必要です。

### ファビコンを設定
デフォだとコメントアウトされていますが、ファビコンを `/public/favicon.ico`に配置したらコメントアウトをはずしてね、と丁寧にかいてあります。

```js:17-18行目
// uncomment after placing your favicon in /public
//app.use(favicon(__dirname + '/public/favicon.ico'));
```

### ログ出力方法を設定

```js:19行目
app.use(logger('dev'));
```

### パラメータのパース方法を設定

```js:20行目
app.use(bodyParser.json());
```

### パラメータのパースで利用するライブラリを設定

```js:21行目
app.use(bodyParser.urlencoded({ extended: false }));
```

urlエンコードの際に、[querystringライブラリ](https://nodejs.org/api/querystring.html)を使うか、[qsライブラリ](https://www.npmjs.com/package/qs#readme)を使うかの設定。falseが前者。

### クッキーのパーサーを設定

```js:22行目
app.use(cookieParser());
```

### 静的ファイルが配置されているディレクトリを設定

```js:23行目
app.use(express.static(path.join(__dirname, 'public')));
```

[express.static(root, [options])](http://expressjs.com/api.html#express.static) は、expressにビルトインの唯一のミドルウェアで、rootディレクトリ配下に配置している静的ファイルへのルーティングを自動で行ってくれます。
例えば、`myapp/public/images/hoge.png`や`/public/license.html`といったものにアクセスすることができるようになります。

### ルーティング設定を適用する

```js:25-26行目
app.use('/', routes);
app.use('/users', users);
```

こういうふうに1階層まではapp.jsに書いて、残りは各ルーティングモジュールに任せるという設計かなと思います。

### エラーハンドリング

#### HTTPステータス404エラー

```js:28-33行目
// catch 404 and forward to error handler
app.use(function(req, res, next) {
  var err = new Error('Not Found'); 
  err.status = 404; 
  next(err);
});
```

errorオブジェクトを作成し、`next(err)`で次のミドルウェアに処理を渡しています。

#### development環境でのエラー出力処理

```js:37-47行目
// development error handler
// will print stacktrace
if (app.get('env') === 'development') { 
  app.use(function(err, req, res, next) { 
    res.status(err.status || 500); 
    res.render('error', { 
      message: err.message, 
      error: err
    }); 
  }); 
}
```

envは、デフォルトでは `process.env.NODE_ENV` か `“development”` に設定されています。
app.jsでは、何も設定していないので、このスコープに入ってくるようになっています。
参考: http://expressjs.com/api.html#app.set

app.useの基本形は、`app.use([path,] function [, function...])`で、pathが省略されている場合は、'/'になります。つまり、どの階層でエラーが起きても、ここに入ってくるということです(多分)。
で、res.renderのところは、前述の[res.renderとは](http://qiita.com/mito_log/items/735f7079f99ec78ea7e6#resrender%E3%81%A8%E3%81%AF)と同じです。

#### production環境でのエラー出力処理

```js:51-57行目
// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
  res.status(err.status || 500);
  res.render('error', {
    message: err.message,
    error: {}
  });
});
```

エラーメッセージのみで、errorの詳細は吐出されません。

## モジュールとして本アプリを出力

```js:60行目
module.exports = app;
```

本app.js自体も、外部モジュールとして利用できるようになっている、ということでしょうか。。

最後歯切れわるかったですけど、こんな感じです。間違いや、こうだよということがあればご指摘お願いします！