Node.js学んでみた ~その② ルーティング編~

https://www.nodebeginner.org/index-jp.html#javascript-and-nodejs
↑node.jsについてすごくわかりやすく書かれた入門書？です。これを元に学習!

【前回】
[Node.js学んでみた ~その① 簡易サーバー作成編~](https://qiita.com/irico/items/d30051dbbc22a081922b)


猫でもわかる〜、猿でもわかる〜、って発祥はなんなんでしょうね？
私は昔ゲームを作りたくて「猫でもわかるC言語」というサイトを１６年前ぐらいに見た記憶があるので、もうその頃からはあったはずです。一行も理解できなかった猫以下の頃でした。（小学校２、３年生）

本題。

##モジュールを作ってみる
前回学んだサーバーを建てるコードを、別モジュールに写します。

```javascript:server.js
var http = require('http');

function start(){
  var html = require('fs').readFileSync('src/index.html')
  var server = http.createServer(function(request,response){
    response.writeHead(200,{'Content-Type':'text/html;charset=utf-8'});
    process.on('uncaughtException', (e) => console.log(e));

    response.end(html);
  })


  server.listen(8080,'127.0.0.1');
  console.log("Server has started");
}

exports.start = start;
```

```javascript:app.js
var server = require("./server");
server.start();
```

出したいコードをファンクション化して、`export.xxx`　で登録！
あとは呼び出したいファイルで`require`すればいいですね。
ターミナルで、
```
node app.js
```
とすればhttp://localhost:8080/ にちゃんと繋がります。

##ルーティングをやる
**ルーティング**っていうのはHTTPリクエストに応じてコードの表示先を変えることです。これができればグッとできることが増えそうですね。

使う道具（モジュール）たち！
`url`・・・URLの各部分（リクエストパスとか）を抽出するメソッドを提供
`querystring`・・・リクエストパラメータのクエリ文字をパースできるメソッドを提供

HTTPリクエストをこれらを使ってやっつけます。

```javascript
var http = require('http');
var url = require('url'); //urlモジュール追加

function start(){
  var html = require('fs').readFileSync('src/index.html')

  var server = http.createServer(function(request,response){
    var pathname = url.parse(request.url).pathname; 
    console.log("Request for" + pathname + " received."); //パス表示
    response.writeHead(200,{'Content-Type':'text/html;charset=utf-8'});
    process.on('uncaughtException', (e) => console.log(e));

    response.end(html);
  })


  server.listen(8080,'127.0.0.1');
  console.log("Server has started");
}

exports.start = start;
```
url部分をパチパチ打ち込んで変えてみると、ちゃんとターミナルにそれが表示されるのがわかるかと思います。
これを使えばルーティングできますね。

このままでは管理しずらいのでサーバーとルーターの機能を分けます。

```javascript:router.js
function route(pathname) {
  console.log("About to route a request for " + pathname);
}

exports.route = route;
```
パス表示部分のファイルですね。

```javascript:app.js
var http = require('http');
var url = require('url');

function start(route){
  var html = require('fs').readFileSync('src/index.html')
  var server = http.createServer(function(request,response){
    var pathname = url.parse(request.url).pathname;

    route(pathname); //ルーティング部分

    response.writeHead(200,{'Content-Type':'text/html;charset=utf-8'});
    process.on('uncaughtException', (e) => console.log(e));
    response.end(html);
  })


  server.listen(8080,'127.0.0.1');
  console.log("Server has started");
}

exports.start = start;
```
サーバー部分の処理になります。routeを呼び出していますね。

```javascript:app.js
var server = require("./server");
var router = require("./router");
server.start(router.route);
```
２つのモジュールを呼び出して、関数を読み込んで実行します。

これで機能別にモジュール化できたので、あとはルーティングの肝部分です！
リクエストハンドラーは増減が激しいのでオブジェクトとして登録します。
まずはrequestHanders.jsというファイルを以下のように作ります。

```javascript:requestHanders.js
function start(){
  console.log("startが呼ばれました");
}

function upload(){
  console.log("uploadが呼ばれました");
}

exports.start = start;
exports.upload = upload;
```
お次にこれらをapp.jsで呼び出して、オブジェクトとして登録。
startに関しては、`/`でもルーティングできるようになっていますね。
オブジェクトをsever.startに第二引数として渡しています。

```javascript:app.js
var server = require("./server");
var router = require("./router");
var requestHandlers = require("./requestHandlers"); //呼び出し

var handle = {} //オブジェクト化
handle["/"] = requestHandlers.start;
handle["/start"] = requestHandlers.start;
handle["/upload"] = requestHandlers.upload;

server.start(router.route,handle);
```

次はappから呼び出されているserver.jsを修正します。
`function start`の第二引数`handle`を増やしてあげて、
`route`関数呼び出し時の第一引数にそのまま`handle`を入れています。


```javascript:server.js
var http = require('http');
var url = require('url');

function start(route,handle){
  var html = require('fs').readFileSync('src/index.html')
  var server = http.createServer(function(request,response){
    var pathname = url.parse(request.url).pathname;
    console.log("Request for" + pathname + " received.");

    route(handle,pathname);

    response.writeHead(200,{'Content-Type':'text/html;charset=utf-8'});
    process.on('uncaughtException', (e) => console.log(e));
    response.end(html);
  })


  server.listen(8080,'127.0.0.1');
  console.log("Server has started");
}

exports.start = start;
```

最後に`router.js`の修正です。

```javascript:router.js
function route(handle,pathname){
  console.log("About to route a request for " + pathname);
  if(typeof handle[pathname]==='function'){
    handle[pathname]();
  }else{
    console.log("No request handler found for" + pathname);
  }
}

exports.route = route;
```

`handle[pathname]`がfunctionである時、つまり存在する時は
`handle[pathname]();`、つまりrequestHandlers.jsの関数たちが実行されます。
functionでない時、つまり存在しない時はエラーメッセージを`console.log`で出してあげていますね。

モジュールをたくさん分離していますが、おかげで各機能が明白でいい感じです。

```
Server has started
Request for/ received.
About to route a request for /
startが呼ばれました
```
http://localhost:8080/ にアクセスすると上記のようになります。

```
Request for/upload received.
About to route a request for /upload
uploadが呼ばれました
```
http://localhost:8080/upload にアクセスすると上記のようになります。
ルーティング成功です！
（※faviconに関するメッセージは省略しています）