Express(Node.js)チュートリアル

# 概要
- MDNのExpressについてのチュートリアルを参考にまとめてみました。
    - [Express/Node introduction](https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/Introduction)
- Nodeのインストールについては、別の記事をみてください。

# まずNode.jsについて

- JavaScriptのサーバーサイドのツールかつアプリケーション。
- JavaScriptはブラウザ上で動くイメージがあるが、サーバサイドもかける！！
- ブラウザ用のAPIは取り除き、OS用のAPI(ファイルへのアクセスとか)やHTTP用のAPI群を持っている。

# Node.jsのウェブサーバとしての利点

- スループットとスケーラビリティを持っている。
- ブラウザとサーバサイド両方ともJavaScriptで記述できる。
- node package manager (NPM) を利用すれば、優れたパッケージを再利用できる。パッケージの依存関係なども扱える。楽。

# 簡単なwebサーバのコード例

- 以下で簡単にNodeのHTTPモジュールで、ウェブサーバを起動できる。

```javascript:app.js
// Httpのモジュールの読み込み
var http = require("http");

// 8000番ポートでHTTPサーバ起動
http.createServer(function(request, response) {

   // レスポンスで返すHTTP header(with HTTP status Content type)
   response.writeHead(200, {'Content-Type': 'text/plain'});

   // レスポンスで返すbody
   response.end('Hello World\n');
}).listen(8000);

// 起動ログ
console.log('Server running at http://127.0.0.1:8000/');
```

```shell
// サーバプロセス起動
$ node app.js
```

http://127.0.0.1:8000/
にアクセスすると、HelloWorldのテキストが返されます。

# Expressについて

- ExpressはもっともポピュラーなNodeのウェブフレームワーク。
- 他の有名なNodeのウェブフレームワークの元にもなっている。
- 以下の仕組みを提供する。
    - リクエストに対して、異なるURLパスで、HTTP verbsと共にハンドラーを書く。
    - "view" というrendering enginesをよく利用する。(GUIを伴う場合)
    - テンプレートの場所や、ポートなどの一般的なwebアプリケーションの設定を扱う。
    - リクエストを扱う過程で、"middleware"という付加的なリクエスト処理を加えることができる。(middle ware pattern)

- Expressのmiddlewareとして、たくさんのライブラリが作られている。
    - cookies, sessions, user logins, URL parameters, POST data, security headersなどを扱うライブラリ


# HelloWorld Express(簡単に使ってみる)

- ExpressでHelloWorld。

```javascript:app.js
const express = require('express');
const app = express();

app.get('/', function(req, res) {
  res.send('Hello World!');
});

app.listen(8000, function() {
  console.log('Example app listening on port 8000!');
});
```

- app(慣例の名前付け)のオブジェクトは、アプリケーションの振る舞いの操作に関するメソッドを持つ。
    - HTTPルーティングのメソッド
    - middlewareの設定
    - viewのレンダリング
    - テンプレートエンジンの登録
    - アプリケーションの設定変更など

- app.get()
    - 「/」のパスにアクセスされるたびに呼び出されるコールバック関数(functionの部分)を定義する。
    - コールバック関数はrequestとresponseを引数として持ち、responseでsend()を呼び出すことで、「Hello World!」を返す。

# Node.jsのモジュールについて

- モジュールはJavaScriptのライブラリで、require()関数でインポート可能。
- Express自体もモジュールで、ExpressアプリケーションでDBやミドルウェアのライブラリを利用可能。
- メンテナンスの観点から、自作でモジュールを作りたくなるはず。

- 以下のようにexportsすることでmoduleとして利用できる。

```javascript:square.js
exports.area = function(width) { return width * width; };
exports.perimeter = function(width) { return 4 * width; };
```

- インポートはこう。

```javascript:app.js
var square = require('./square'); // Here we require() the name of the file without the (optional) .js file extension
console.log('The area of a square with a width of 4 is ' + square.area(4));
```

- module.exportsを使うことで、一度にオブジェクトとしてexport可能。

```javascript:square.js
module.exports = {
    area: function(width) {
        return width * width;
    },

    perimeter: function(width) {
        return 4 * width;
    }
};
```

# 非同期APIについて

- JavaScriptは同期処理APIより非同期処理APIの方がよく利用される。
- Nodeはシングルスレッドで動く。
    - シングルスレッドということは全てのサーバへのリクエストを一つのスレッドで捌く。
    - これはスピードとルーティングの観点で利点があるが、同期的な関数を実行して、時間がかかるとパフォーマンスに大きく影響する。
- 非同期処理APIの完了通知を受ける方法はいくつかある。
    - もっとも一般的な方法は、完了時に呼び出されるコールバック関数を登録すること。
- 時々コールバック地獄(ネストしまくること)にハマるが、減らせる解決方法もあるので調べること。(Promiseとか)

# route handlers

- Hello Worldの例で、ルーティングメソッド(get)でコールバックを実装したが、send()の他にもレスポンス用のメソッドがある。
    - res.json()
    - res.sendFile()
- 参考: https://expressjs.com/en/guide/routing.html#response-methods

- もちろんgetの他にもルーティングメソッドが用意されている(HTTP verbsに対応するもの)
    - post(), put(), delete() etc

- app.all()という特別なルーティングメソッドもある
    - すべてのHTTP methodのレスポンスで呼ばれる

```javascript:app.js
app.all('/secret', function(req, res, next) {
    console.log('Accessing the secret section ...');
    next();  // pass control to the next handler
    });
```

- グループルーティングのハンドラーも便利。(express.Router)
    - 例: a site with a Wiki might have all wiki-related routes in one file and have them accessed with a route prefix of /wiki/

```javascript:wiki.js
// wiki.js - Wiki route module

const express = require('express');
const router = express.Router();

// Home page route
router.get('/', function(req, res) {
    res.send('Wiki home page');
    });

// About page route
router.get('/about', function(req, res) {
    res.send('About this wiki');
    });

module.exports = router;
```

- ふたつのrouterができている。
    - '/wiki/'
    - '/wiki/about/'

```javascript:app.js
const wiki = require('./wiki.js');
const express = require('express');
const app = express();

app.use('/wiki', wiki);

app.listen(8000, () => {
    console.log('Example app listening on port 8000');
});
```

# middlewareを使う

- MiddlewareはExpressアプリの中で多岐に渡り利用される。
    - 静的ファイルのサービングや、エラーハンドリングetc
- route関数はHTTPのリクエストレスポンスのサイクルを、HTTPクライアントになにかしらを返して終わらせるが、middleware関数は大抵リクエスト中、レスポンス中に何かしらの処理を実行し、次の関数(middlewareとかhandlerとか)を呼び出す。
- middlewareが呼ばれる順番は開発者次第。
- サイクルを終了させない場合は、next()メソッドを呼んで、次のmiddleware関数にコントロールを渡さなければならない。そのままあとリクエストがhangingするから注意。

- 多くのアプリはthird-partyのmiddlewareを利用するはず。
    - できるだけcookieやlogging, sessionなどめんどくさいことは簡潔にしたいから。
- third-partyのmiddlewareを利用するにはまずNPMでインストール必須。

## 例: morgan(HTTPリクエストのlogger middleware)
まずインストール

```shell
$ npm install morgan
```

use()を呼ぶことでmiddlewareを追加する

```javascript:app.js
var express = require('express');
var logger = require('morgan');
var app = express();
app.use(logger('dev'));
...
```

- (Note): middlewareとrouting関数は宣言された順番に呼ばれる。
    - middlewareの中には呼ばれる順番が重要なものがあるので注意。
        - session middleware はcokie middlewareに依存する→cookie middlewareを先に呼ばなければならない

- 自分でmiddlewareを作成できる。
- middleware functionとroute handler callbackの違いは、middlewareは3つ目の引数nextを持つ。
- app.use()もしくはapp.add()で連鎖的にmiddlewareを追加できる。
    - 追加の仕方は、「middlewareをすべてのレスポンスに適用したいか」もしくは「特定のHTTPverb(GET,POST etc)のレスポンスに適用したいか」で変わってくる
    - どちらの場合でも、app.use()を呼ぶ際にroutesを明示する必要がある。routeはオプションだけど。

```javascript:app.js
const express = require('express');
const app = express();

// middleware functionの例
const a_middleware_function = function(req, res, next) {
    // ... ここで何かしらの処理
    console.log('a_middleware_functionが呼ばれた');
    next();
}

// Function added with use() for all routes and verbs
app.use(a_middleware_function);

// Function added with use() for a specific route
app.use('/someroute', a_middleware_function);

// A middleware function added for a specific HTTP verb and route
app.get('/', a_middleware_function);

app.listen(8000);
```

- より詳しい参考
    - 使い方: https://expressjs.com/en/guide/using-middleware.html
    - 書き方: http://expressjs.com/en/guide/writing-middleware.html


# databasesの利用

- ExpressはNodeが使えるdatabaseなら利用可能。
    - PostgreSQL, MySQL, Redis, SQLite, MongoDB, etc.
- npmでdriverを入れる必要がある。

```shell
$ npm install mongodb
```