オリジナルKdB(科目検索)を作ってみよう -5- Express.jsでWEBアプリ整形編

### これまでの記事
- [オリジナルKdB(科目検索)を作ってみよう -1- Node.jsセットアップ編](https://qiita.com/tkkrr/items/2f0d93b6d0c758a88037)
- [オリジナルKdB(科目検索)を作ってみよう -2- パース編](https://qiita.com/tkkrr/items/d8a87b4f598b1b107266)
- [オリジナルKdB(科目検索)を作ってみよう -3- データで遊ぶ編](https://qiita.com/tkkrr/items/8c0f66312212420114a0)
- [オリジナルKdB(科目検索)を作ってみよう -4- Express.jsでWEBアプリことはじめ編](https://qiita.com/tkkrr/items/5cafa77c104b11d76a16)

### 前回の要約
- Node.jsの定番WebフレームワークのExpress.jsで遊んだ
- Hello,World と Routing をした

<img width="1241" alt="スクリーンショット 2019-02-22 16.11.47.png" src="https://qiita-image-store.s3.amazonaws.com/0/245014/3d0c6b57-d3a9-1be1-4166-f9068a2f9771.png">

# この記事を読む前に
この記事はシリーズものです。前回の記事を読んである前提で話を進めるので注意してください。
また、ある特定の人にしかわからない単語が出現する可能性が高いです。あらかじめご了承ください。

### この記事での開発環境
- MacOS 10.14.3
- Visual Studio Code 1.31.1
- Node.js LTS 10.15.1

# 今回やること
- パースした情報をExpress.jsで処理する
- Express.jsと相性のいいテンプレートエンジン**Pug**を書く

キーワード **モジュール化, テンプレートエンジン, Pug**

# データを流し込もう
それでは、Express.jsについてある程度理解したので、パースしてきた情報をExpress.jsで処理しましょう！まずは`index.js`を使いやすいように**モジュール化**します。`index.js`を以下のように丸っと書き換えてください

```javascript:index.js
const fs = require('fs');
const parse = require('csv').parse;
const iconv = require('iconv-lite');

// モジュールの関数を作ります
const myParser = ( filename, decoding ) => {

    // パースしたデータを入れる配列
    const dataArray = []; 

    // ①
    const parser = parse( (err, data) => {
        data.forEach( (element, index) => {
            dataArray.push(element)
        });
    });
    
    // ファイルストリームから読み込み → デコード → パース
    fs.createReadStream( __dirname + '/' + filename )
        .pipe( iconv.decodeStream(decoding) )
        .pipe( parser );

    // パースした結果
    return dataArray;
}

// ②
module.exports = myParser;
```

これでパース処理を`index.js`以外でも使えるようになりました！ 解説していきます。

#### ① パース情報を配列を作成
```javascript
const parser = parse( (err, data) => {
    data.forEach( (element, index) => {
        dataArray.push(element)
    });
});
```

これまでは`dataArray.push()`の部分が`console.log()`でした。これは最終的に配列を返したいのでこのような記述になります。`push()`は配列の破壊的な変更になるので、気になる方は`concat()`を使って副作用のないコードに変更することをオススメします。

#### ② モジュール化！
```javascript
module.exports = myParser;
```
ここでは、`index.js`の**モジュール化**をしています。モジュール化すると、他のjavascriptファイルから自由に呼び出すことができるので一気に便利になり、コードの見通し、メンテナンス性が良くなります。今回は`myParser()`のみをモジュールに含めていますが、もちろん複数選択可能です。その場合は以下のようになります。

```javascript
module.exports = { 
    hoge: myFunction1,
    fuga: myFunction2,
    nyan: myfunction3
}
```

使用する側は`require文`を使うことでモジュール化された関数を使うことができます。`app.js`を変更して確認しましょう

```javascript:app.js
const app = require("express")(); // ショートハンドに書き直してます
const getParseData = require("./index"); // 作ったモジュールを読み込みます！

// index.jsの関数を使う！
const dataArray = getParseData( "kdb.csv", "shift_jis" );

// とりあえず全表示...
app.get( "/", (req, res) => {
    res.send(dataArray);
});

app.listen(3000); // ポート番号3000でサーバ起動！
console.log("server started!!");
```
実行します。

```shell
$ node app.js
```

さて... それではブラウザで http://localhost:3000/ にアクセスしてみましょう。

<img width="1440" alt="スクリーンショット 2019-02-23 18.19.47.png" src="https://qiita-image-store.s3.amazonaws.com/0/245014/bb484b70-c8af-b34c-882a-d99226b284d2.png">

# ｷｬｧｧｧｯ!!!! ﾋｮｳｼﾞｻﾚﾀｧｧｧｯ!!!!
圧倒的な文字列... でもちゃんと表示されているので成功です！ちゃんとパースしたものがブラウザで表示されていますね！整理すると

- モジュール化に成功
- パース成功
- Express.jsでRouting成功

という、なんやかんやでめんどくさい部分は終わりました！それでは、これをHTMLに整形していきましょう。

# テンプレートエンジンに任せよう
Express.jsの`res.send()`に直接HTMLを書いてもいいのですが、**絶対にやめましょう**。なぜかというと、**フロントエンド(View)部分の自由度を下げてしまったり、意図しない挙動が発生してしまったり、表示バグを招いてしまったり**といいことが一つもないからです。なので、基本的には必要な情報のみ or JSON などでレスポンスすることを心がけます。

```javascript
app.get( "/", (req, res) => {
    res.send(dataArray);
});
```

今回は配列をレスポンスで返したので、この情報をHTMLで処理していきます。「...ってどうやって？」となりますが、Express.jsにはデータをいい感じにHTMLに流し込んでくれる「**テンプレートエンジン**」という機能があります！これまたいくつかありますが、今回はその中の[**Pug**](https://pugjs.org/api/getting-started.html)を使っていきます

書き方は以下の記事に詳しく書いてあります

- [【Pug】ゴリラでもわかるJade改めPug入門](https://blog.mismithportfolio.com/web/20160326pugbegin)
- [Getting Started - Pug](https://pugjs.org/api/getting-started.html)

それでは、Pugをインストールしましょう。

```shell
$ npm install pug
```

`app.js`を編集します。

```javascript:app.js
const app = require("express")();
const getParseData = require("./index");

const dataArray = getParseData( "kdb.csv", "shift_jis" );

// テンプレートエンジンをセット！
app.set("view engine", "pug");

// 後で解説します
app.get( "/", (req, res) => {
    res.render("html.pug", { 
            state: dataArray,
            word: "全検索"
    });
});

app.listen(3000); // ポート番号3000でサーバ起動！
console.log("server started!!");
```

ちょいとわかりづらいですが、とりあえずpugのファイルを作りましょう(**テンプレートエンジンでは`/views/`ディレクトリにテンプレートファイルを置く必要があります。**)

```haml:views/html.pug
- const values = state

doctype html
html
    head
        title 検索 : #{word}
        meta(charset="UTF-8")
    body
        h1 開設科目一覧
        ul
            each value in values
                li #{value[0]} : #{value[1]}
```

ぱっと見全然わかりませんね笑。でもPugの記述ルールは難しくないので、[こちらの記事](https://blog.mismithportfolio.com/web/20160326pugbegin)を軽く読めばわかります。超意訳すると、Pythonみたいに**インデント**でHTMLのDOM構造を書き表したものです。記述の中にプログラムちっくな処理もかける(`- const values = state`や`each value in values`など)優れモノです。

では実行してみましょう。

```shell
$ node app.js
```

<img width="1440" alt="スクリーンショット 2019-02-23 18.49.39.png" src="https://qiita-image-store.s3.amazonaws.com/0/245014/69d967f9-fe97-c66e-421f-03445f67957a.png">

# 解説
綺麗に表示できましたね！流石に全件となると同期処理では重いですが、無事表示できました！それでは解説です。

```javascript
app.set("view engine", "pug");
```
最初にテンプレートエンジンとしてPugを使うことを明記します。Pugの他にも**ejs**などが使えますが、個人的にはPugの方がコードの見通しが良いため好きです。テンプレートエンジンの使用を宣言したら次です。

```javascript
app.get( "/", (req, res) => {
    res.render("html.pug", { 
            state: dataArray,
            word: "全検索"
    });
});
```

これまで使ってきた`res.send()`ではなく、`res.render()`を使っています。`res.render()`では、第1引数にテンプレートファイルの名前、第2引数にテンプレートファイルに渡したいデータを、それぞれ記述します。今回の場合は`html.pug`に以下のデータ(オブジェクト)を渡しました。

```
{
    state: dataArray,
    word: "全探索"
}
```

一方このデータをもらった`html.pug`ではどのようにデータが処理されるかをみてみます。

```haml:views/html.pug
- const values = state

doctype html
html
    head
        title 検索 : #{word}
        meta(charset="UTF-8")
    body
        h1 開設科目一覧
        ul
            
            each value in values
                li #{value[0]} : #{value[1]}
```

一行目`- const values = state`でExpress.jsからもらった`state`( ... すなわちdataArray)を`values`に格納しています。変数(Express.jsからもらったデータでも、Pug内で定義した変数でも)をHTMLに流し込むときは`#{変数名}`と記述します。

`each value in values`は`values`の中身一つ一つに処理をするので`state`(dataArray)の各要素の0番目と1番目をひたすら列挙してくれます！だから、科目番号と科目番号名だけが表示されているということですね

<img width="1440" alt="スクリーンショット 2019-02-23 18.49.39.png" src="https://qiita-image-store.s3.amazonaws.com/0/245014/69d967f9-fe97-c66e-421f-03445f67957a.png">

なんとなくわかりましたか？
(例えたくても、例えが思いつかないのでそのまま説明するしかないのです...)
とりあえずわかったね！先に進もう！

# 簡易的な検索機能を作ろう
前回のRoutingの手法を活かして、検索機能を作っていきます。それでは`app.js`を編集しましょう。

```javascript:app.js
const app = require("express")();
const getParseData = require("./index");

const dataArray = getParseData( "kdb.csv", "shift_jis" );

app.set("view engine", "pug");

app.get( "/", (req, res) => {
    res.render("html.pug", {state: dataArray ,word: "全検索"});
});

//  http://localhost:3000/〇〇 で検索できるように！
app.get( "/:word", (req, res) => {
    const state = [];
    const matchReg = new RegExp(req.params.word); // 正規表現の準備
    
    dataArray.filter( (data) => {
        return data[1].match(matchReg) // 科目名で検索
    }).forEach( (element, index) => {
        state.push(element);  // マッチしたものを格納
    });

    res.render("html.pug", {
        state: state,
        word: req.params.word
    });
});

app.listen(3000);
console.log("server started!!");
```

しれーっと`filter`や`RegExp()`、正規表現を使ってますが、javascriptで標準搭載の便利なものなのでどんどん使っていきます。詳しくは以下の記事を読みましょう。

- [Array.prototype.filter() | MDN - Mozilla](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/filter)
- [RegExp | MDN - Mozilla](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/RegExp)
- [String.prototype.match() | MDN - Mozilla](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/match)

実行します

```shell
$ node app.js
```

これで簡易的な検索機能を実装しました。それでは http://localhost:3000/コンテンツ などで検索してみましょう。

<img width="1440" alt="スクリーンショット 2019-02-23 19.30.53.png" src="https://qiita-image-store.s3.amazonaws.com/0/245014/a60c239b-90d9-44e3-9ccb-d4d158f59e89.png">

# 検索できたよ！やったね！
科目名に「コンテンツ」が含まれる科目だけが出力されました！(簡易的ではありますが)検索機能の完成です！やったね！

もちろん、すべてのユーザにURLを直打ちしてもらうわけにはいかないので、フォームなどを作って検索させると利便性が向上すると思います。今回はパパッと作るために省略しましたが、余裕があったら是非実装してみてください！

もう少し見栄えを良くしたい場合はCSSを書いて、俺専用ッ！なものを作ってみると面白いです。

次回はいよいよこのWEBアプリを公開していきます。簡単にWEBアプリを公開できる[**heroku**](https://jp.heroku.com)を使っていきましょう！乞うご期待！


## 今回のあとがき
Express.jsは軽量WEBフレームワークで、大きな人気を博しています。というのも、機能を最小限に絞り、軽量で動作が早く、すぐに導入できるからだと思います。特に、今回は`html.pug`(View)に`index.js`(Model)がパースした情報`app.js`(Controller)で処理しています。今回のような設計モデルをMVCモデルと言います。MVCとは **Model View Controller** の頭文字です。

- Model ... Controllerの命令に基づいて実際にデータを処理する部分
- View ... 実際にユーザが見ている部分。ユーザのアクションに基づいてControllerに処理をお願いする。
- Controller ... Viewからの命令をもとにModelに処理を命令したり、Modelの情報をViewに渡したりする。

例えば、ユーザ認証ページで考えてみるとわかりやすいです。

`View` ユーザがID,Passを入力。
`View` Viewはその情報をControllerに通知。
`Controller` ID,Passが正しいかをModelに確認するよう命令
`Model` 受け取ったIDをもとに該当ユーザを検索。該当ユーザをControllerへ通知
`Controller` Modelからもらったユーザ情報と入力されたID,Passを検証。結果をViewへ通知。
`view` Controllerからの情報を表示

といった感じです。もちろんこれは100%は正解ではありません。「ModelはControllerからの命令をもとに直接Viewに情報を渡す」とか「Controllerがユーザの行動を監視。アクションに応じてModelに情報を用意させてViewに取りにいかせる」とかとか。「なんやわけわからん難しい」ですがこれらも立派なMVCモデルです。

分業させることでそれぞれの処理に集中させることが目的であり、プロジェクトが大きくなっても複雑になりすぎることがなく理解しやすいのが利点です。フルスタックWebフレームワークの [**Ruby on Rails**](https://rubyonrails.org) ではMVCの設計思想で進むことが基本です。ですが、Viewに関する自由度が幾らか下がってしまうのが難点だったりします。

Express.jsの最小構成ではMVCで言うところのController機能のみを提供します(もちろん最小構成で使うことはないのでModelもつけます)。その高い汎用性・カスタマイズ性が大変魅力的でした。ささっと何かを作りたい場合にExpress.jsは便利です。きっとこれからも人気を博していくことでしょう。

一方、フロントエンドのjavascriptでは有名なフレームワークが3つあります。[**Angular.js**](https://angularjs.org), [**Vue.js**](https://jp.vuejs.org/index.html), [**React.js**](https://reactjs.org) です。どれも非常に高機能でありますが、それぞれの得意とする分野はかなり違います。直感的でわかりやすく、レファレンスが充実しているVue.jsは人気です。フルスタックで強固なAngular.jsは大きなプロジェクトでは頼もしいですし、React.jsのコンポーネントモデルに特化した姿勢、再利用性の高さは魅力的です。

バックエンドとフロントエンドどちらをメインにしようか迷っている人間がここに一人。
私は一体どこへ向かっていくんですかね〜

ではでは

次の記事 → [オリジナルKdB(科目検索)を作ってみよう -6- 本番環境Herokuにデプロイ編](https://qiita.com/tkkrr/items/db58c25ac65da30531e9)

#### 参考サイト
- [Model View Controller - wikipedia](https://ja.wikipedia.org/wiki/Model_View_Controller)
- [JavaScript: フレームワーク React/Vue/Angularについて](https://qiita.com/fumio_nonaka/items/13eb7da8224bf93c67b5)
- [Express.js](https://expressjs.com)