js初心者のnode.js自習メモ（2）アップローダを作ろう②～ルータ構成とURLのパース＋おまけ～

#これまでのあらすじ
[js初心者のnode.js自習メモ（1）](http://qiita.com/quma_forest/items/310f38d07bd44ccf5a83)
[js初心者のnode.js自習メモ（2）アップローダを作ろう①～全体の見通し～](http://qiita.com/quma_forest/items/fa9423eca272ff0d288a)

前回、全体の構成は4ファイルでアップローダつくるぜ！
ということでで今回はちゃっちゃか行きます。
1. exportsとrequireを使ってファイルの分け方を確認します
2. URLをパースするところを作ります

#require("module")
httpサーバをつくるときにすでにモジュールの呼び出しはやってますね。
　　`var http = require("http");`
でhttpモジュールを呼び出します。
ユーザモジュールを使う場合は次のようにファイルパスを記述します。
　　`var foo = require("./bar");`
拡張子`.js`は省略していいみたいです。
省略すべきかどうかは一考の余地ありですが。

ところでnodeではモジュールって呼ぶんですかね。
個人的にはライブラリと何が違うのかなって思いますが。

#exports.function
今度は、呼び出される側に以下の記述をします。
　　`exports.foo = bar;`
これで
「`function bar()`を外部モジュールで`function foo()`として使っていいよ」
という意味合いになります。

#urlモジュール
便利なことにURLにいろんなことできるurlモジュールがあるので使います。
これでpathnameとqueryを分けてルータに投げれば大まかな仕組みはできそうです。

urlモジュールを呼び出して、pathnameを抽出するためにparseを使い
リクエストされたpathnameをプレーンテキストで返すhttpサーバにしてみます。

```js:server.js()
// server.js
var http=require("http");
var url =require("url"); //url文字列の抽出をする

function start(){
	function onRequest( request, response ){
		//urlのリクエストパス抽出
		var pathname = url.parse(request.url).pathname; 
		console.log("Request for "+ pathname +" recieved.");

		response.writeHead(200,{"Content-Type": "text/plain"});
		response.write("your request is \""+ pathname +"\"");
		response.end();
	}

	http.createServer(onRequest).listen(8888);
	console.log("Server has started");
}

exports.start = start;
```
ついでにstart()を外部から使えるようにしているので、
index.jsから呼び出して使いましょう。

```js:index.js
//index.js
var server = require("./server"); //server.jsの呼び出し

server.start();
```

#パース結果の確認
ローカルホストの/startにリクエストしたキャプチャです。
ブラウザでもコンソールログでも正しく動作しています。
キャプチャに入れ忘れましたがnodeのバージョンはv0.10.26です。
![cap1.JPG](https://qiita-image-store.s3.amazonaws.com/0/115000/b27c2a26-06b4-c83e-7bf5-0ff534262afb.jpeg)

もう少し長いパスにリクエストしてみます。
![cap2.JPG](https://qiita-image-store.s3.amazonaws.com/0/115000/aca7afd2-c119-cc11-e2f9-037f3c3fff9a.jpeg)

次はクエリを混ぜてみます。
パス部分だけ抽出できてますね。
![cap3.JPG](https://qiita-image-store.s3.amazonaws.com/0/115000/3bd0a094-7aa4-e00d-802c-f785e1b1dea1.jpeg)

#ルータ構造をつくる
URLをパースできるようになったので、それをルータに渡す構造を作ります。
ルータはパスをみて、リクエストに合った動作をする関数を呼ぶのがお仕事。
うーん、手配師かな？

とりあえず、今回はそこまで作らず、ちゃんとパスが渡せることを確認します。
index.js, server.js, router.jsの3つを動作させます。

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

exports.route = route;
```
```js:server_ver2.js
// server.js
var http=require("http");
var url =require("url");

function start(route){
	function onRequest( request, response ){
		//urlのリクエストパス抽出
		var pathname = url.parse(request.url).pathname;
		console.log("Request for "+ pathname +" recieved.");

		route( pathname ); //パスをルータに渡す

		response.writeHead(200,{"Content-Type": "text/plain"});
		response.write("your request is \""+ pathname +"\"");
		response.end();
	}

	http.createServer(onRequest).listen(8888);
	console.log("Server has started");
}

exports.start = start;
```
```js:index_ver2.js
//index.js
var server = require("./server"); //server.jsの呼び出し
var router = require("./router"); //router.jsの呼び出し

server.start(router.route); //route関数を引数にする
```
たいしたことやってないし説明カット。

##確認
![cap4.JPG](https://qiita-image-store.s3.amazonaws.com/0/115000/e6dafd60-33c4-606c-263b-87d40910c79e.jpeg)

リクエストパス /aiueo が関数routeまで伝達できています。
次回はこいつを使って、URLに合った動作をさせます。

#querystring.parseでつまづいた話
URLを取り扱うurlモジュールと同様に、
queryを取り扱うquerystringモジュールがあるんですが、
これのparseでちょっとつまづいた。
くだらないけどアウトプットしておきます。

##問１：次の（アホな）間違いを指摘せよ
次の間違い、パッとわかります？

```js:parse_ng.js
var url =require("url"); //url文字列の抽出をする
var querystring =require("querystring"); //query文字列の抽出をする

var pathname = url.parse(request.url).pathname; 
var query    = url.parse(request.url).query;
var foo      = querystring.parse(request.url).foo;
var fuck     = querystring.parse(request.url).suck;
```

##デバッグしてみる
何処の記述がおかしいかわかりましたか？
結果としてどうなるかわかりますか？
それでは動作させてみたキャプチャを確認してみましょう。

![cap5.JPG](https://qiita-image-store.s3.amazonaws.com/0/115000/446391c7-1d06-bec2-349a-4f4fc2e8b361.jpeg)

コンソール出力を見ると、1番目のパラメータfooの値だけ
undefinedになってますね。まれによくあるやつだ。

nodeをインタプリタ実行環境として使って確認してみましょう。
端末から ` $ node ` でnode単体で起動して
`> var query = require("querystring");` で
querystringを呼び出して動作を確認します。

`a=1&b=2&c=3`を引数にしたときと、
`abc?a=1&b=2&c=3`を引数にしたときの違いは以下のとおり。
![cap0.JPG](https://qiita-image-store.s3.amazonaws.com/0/115000/2af696cb-3bc4-1d60-07f9-5f63311d731d.jpeg)

うーん、さっきと同じ現象が再現してますね・・・？
URLやパスとつながったまま渡すとおかしくなるようです。


(゜-゜)…


…( ﾟдﾟ)ﾊｯ!


![cap6.JPG](https://qiita-image-store.s3.amazonaws.com/0/115000/44884816-3c39-f7ae-5e94-73862ae87fc6.jpeg)

1個目のパラメータ名が?でスライスされてない…じゃん…
そりゃあ1個目のパラメータだと思ってたものが、
「ない」んだからundefined返ってきますよね。
URLでも動いてくれるとか勘違い良くない。
プログラマが優しいわけがない。（優しくないのも優しさか？）

ということで、
**querystringはURLが引数として渡されるのを想定していない**
ということがわかりました。そりゃそうだ。

#答え合わせ
と、いうことで、parse_ng.jsを正しく動かすには、
次の記述にしないといけません。

```js:parse_ok.js
var url =require("url"); //url文字列の抽出をする
var querystring =require("querystring"); //query文字列の抽出をする

var pathname = url.parse(request.url).pathname; 
var query    = url.parse(request.url).query;
var foo      = querystring.parse(query).foo; //queryにパースしてから使う
var fuck     = querystring.parse(query).suck; //queryにパースしてから使う
```

![cap8.JPG](https://qiita-image-store.s3.amazonaws.com/0/115000/2a791373-6150-fef2-a30f-17abfb3177ab.jpeg)

#ドキュメントをちゃんと読もう。
[Node.js v5.7.1 Documentation](https://nodejs.org/api/querystring.html#querystring_query_string)や[querystring.js](https://github.com/nodejs/node/blob/master/lib/querystring.js) をパラっと見ると
?より前を捨てたりしてくれません。
デフォルトセパレータは=と&だよってちゃんと書いてます。

**クエリにしてから渡しましょう。**
ちゃんちゃん。