Expressはミドルウェアで開発しよう！

# 概要
仕事でExpressアプリを開発しています。
動作を保証する指標として、テストコードを書いていますが、Expressのジェネレーターが出力してくれる部分（app.jsやserver.js）まで、毎度毎度テストコードを書きたくない思いでいっぱいです。

Expressはミドルウェアの開発に合っているように感じます。（理由は後ほど）
なので、これからはExpressアプリを作るのではなく、Expressミドルウェアを作るようにしましょう！

## この投稿で叶えたい理想像
まず前提として、現状のプロダクトを作っていく考え方として次が挙げられます。

- 1つ1つのプロダクトのサイズを小さく
- 外から持ってこれる場合は外から持ってくる
- 設定・環境のコード化
- 共有して使えるようにする

これらを踏まえて、次のような状態を作っていきたいです。

### 1. 複数のルーター（アプリ）がサーバーの構成を共有
![理想像_1.jpg](https://github.com/walk8243/qiita-express-middleware/raw/master/%E7%90%86%E6%83%B3%E5%9B%B3_1.jpg)

### 2. 複数のサーバーがルーター（アプリ）を共有
![理想図_2.jpg](https://github.com/walk8243/qiita-express-middleware/raw/master/%E7%90%86%E6%83%B3%E5%9B%B3_2.jpg)

## 広めたい考え方
上の理想像を叶える上で、次のようなことを大事にしたいです。

### 1. アプリを主語に
Express上ではルーターですが、アプリケーションの個別設定が主語になるような構成にします。

### 2. サーバーは環境でしかない
サーバーにはメインの処理は書かれていません。
メインの処理が書かれているのはアプリケーションです。
そんなアプリケーションの動作する場所こそがサーバーという環境です。
![考え方.jpg](https://github.com/walk8243/qiita-express-middleware/raw/master/%E8%80%83%E3%81%88%E6%96%B9.jpg)

### 3. アプリが環境を選ぶ
環境に合わせてアプリを作るのではなく、アプリに合わせて環境を選べるように作ります。

# Expressミドルウェア
Expressアプリの開発でミドルウェア単位での開発が合っていると考える理由を挙げていきます。

## 1. Expressの思想と合っている
Expressは「基礎的な Web アプリケーション機能をシンプルな階層」で表現できるように作られています。
ミドルウェアはこの1つ1つの階層を表現するために作られ、使われます。

そして、[Expressミドルウェアの使用](https://expressjs.com/ja/guide/using-middleware.html)にあるように、「Express アプリケーションは基本的に一連のミドルウェア関数呼び出し」です。
Expressでは、 **リクエストレスポンスサイクル** を進めていくことで、アプリケーションの処理が実行されます。その **リクエストレスポンスサイクル** 内でのアプリケーションの処理が、 **一連のミドルウェア関数呼び出し** になります。
そのため、Expressアプリケーションの処理単位はミドルウェアで表現するのが、Expressの思想と合っていると考えています。

## 2. requestオブジェクトとresponseオブジェクトを共有している
ミドルウェア単位での開発を行うことで、クローズドな環境で開発を行うことができます。
その一方で、全ての *requestオブジェクト* と *responseオブジェクト* で同じプロパティを参照します。
その後の処理に引き継ぎたい内容は *responseオブジェクト* へ送り、それ以外はクローズドな環境で安全に開発のようなことができます。

## 3. ミドルウェアの開発者と利用者で共通認識を持ちやすい
開発者は、Expressのミドルウェアという範囲内で開発を行います。
利用者は、Expressのミドルウェアであることは理解して使います。
互いにExpressミドルウェアであるというルールの中にいるのは、静的型付けが主流となっている流れに合っていると思います。

# 開発
開発は **TypeScript** で行いました。
実処理コードは、サーバー部・ルーター部ともに `/src/` 内にあります。
VSCodeでの設定ファイルは、[walk8243/qiita-express-middleware](https://github.com/walk8243/qiita-express-middleware/tree/master/vscode)にあります。

## サーバー部
実際に開発したコードは、 [walk8243/express-middleware-server](https://github.com/walk8243/express-middleware-server) にあります。

### ポイント
- `server.ts` でクラスター化の設定
- `app.ts` でアプリケーションの基本設定
- `router.ts` でアプリ側のルーターを指定
- **npm-scripts** の `postinstall` にビルドを設定
- `package.json` の [bin](https://docs.npmjs.com/files/package.json#bin) で起動スクリプトを設定
- **クラスター数** ・ **ポート番号** ・ **ルーターの場所** をアプリ側から設定できる
    - **環境変数** から設定できる
    - `package.json` の [config](https://docs.npmjs.com/files/package.json#config) から設定できる（環境変数で指定されていない場合）

## ルーター部（アプリケーション）
実際に開発したコードは、 [walk8243/express-middleware-router](https://github.com/walk8243/express-middleware-router) にあります。

### ポイント
- [サーバー部](https://github.com/walk8243/express-middleware-server) をdependenciesに追加
    - `express` や `@types/node` などは [サーバー部](https://github.com/walk8243/express-middleware-server) に任せる
- **npm-scripts** の `start` で [サーバー部](https://github.com/walk8243/express-middleware-server) の起動スクリプトを指定

# まとめ
この投稿のまとめは以下になります。

- **アプリを主語に**
- **サーバー部は後付け**

![まとめ.gif](https://github.com/walk8243/qiita-express-middleware/raw/master/%E3%81%BE%E3%81%A8%E3%82%81.gif)