【Koa】koa-router、mongooseを使ってみる

#### きっかけ
慣れればどうってことないのでしょうが、現時点でほとんど理解できていない。
一つずつ理解していくためのメモです。
とても雑ですが、そのうち綺麗にまとめたい想いもありつつ、とりあえず残します。

#### やりたいこと / わからないこと
Koaを使って、特定のURLにアクセスがあった場合にMongoDBのデータを取得してそれを返すようなものを作りたい（ゆくゆくはそれでAPI開発を...）。
Expressの`app.use`はなんとなく理解できるけど、koa-routerはまた難易度が高くて落とし込むのが難しい...

#### やってみる
少しずつレベルをあげて、理解していこう。 

##### 1. koa-routerに慣れる(1)
koa-routerに慣れるため、特定URLへアクセスがあった時に適当な文字列を返すような仕組みを作ってみよう。
GitHubの内容とほぼ同じです。[(GitHub)alexmingoia/koa-router](https://github.com/alexmingoia/koa-router)	

```javascript:app.js
const Koa = require('koa');
const Router = require('koa-router');

const router = new Router();
const koa = new Koa();
//`app`と名付けられることが多い変数です。Expressと混同しないように今回はあえて`koa`と名付けました。


router.get('/test', (ctx, next) => {
    console.log('get')
    ctx.body = 'Hello World!!';
});

koa.use(router.routes());
koa.use(router.allowedMethods());


koa.listen(3000, () => {
    console.log('Server started!!');
});
```
実行後、`http://localhost:3000/test`にアクセスすると`Hello World!!`が返ってきます。
コンソールログはこんな感じです。

```bash
~]$ node app.js
Server started!!
get
```
なるほど。`koa-router`はKoaのミドルウェアということがこれでなんとなくイメージ掴めますね。
>koa.use(router.routes());

これがとても重要です。これを既述することで初めて`koa-router`でセットした各種ルーティングが使えるようになります。確かに、koa-routerはKoaのミドルウェアなんだから、ミドルウェアだけ作ってもそれをKoaで「このミドルウェアを使うんやで」と教えてあげないと意味がないよという感じですね。

##### ２. koa-routerに慣れる(2)
koa-routerがKoaのミドルウェアであることがなんとなく掴めたので、ここでちょいと実験です!!
どんなルーティングがKoaで認識され、レスポンスが返ってくるのか、よければ妄想してみてください。

```javascript:app.js
const Koa = require('koa');
const Router = require('koa-router');

const koa = new Koa();
const router = new Router();
const router_2 = new Router();


router.get('/test', (ctx, next) => {
    console.log('using router', ctx.method, ctx.url);
    ctx.body = 'Hello World!!';
});

router.get('/test2', (ctx, next) => {
    console.log('using router!!', ctx.method, ctx.url);
    ctx.body = 'Hello World!!';
});


router_2.get('/sample', (ctx, next) => {
    console.log('using router_2!!', ctx.method, ctx.url);
    ctx.body = 'Hello World!!';
});


koa.use(router.routes());
koa.use(router.allowedMethods());

koa.listen(3000, () => {
    console.log('Server started!!');
});
```
以下３通りのルーティングを設定しました。

- http://.../test
- http://.../test2
- http://.../sample

実際に実行してアクセスしてみるとわかりますが、3つ目の/sampleへはアクセスしてもレスポンスが返ってきません。
`/sample`のルーティングは`router_2`オブジェクトを利用して設定しています。ルーティングだけ設定してもKoaに「これを使うんやで」と教えてあげていないので、Koa的には`/sample`へのアクセスがきても知らんわ〜って感じですね。
koa.useに以下二行を追加してあげれば、`/sample`へアクセスした時もいい感じにレスポンスが返ってきます。

```javascript:app.js
//koa.useに追記する。
koa.use(router_2.routes());
koa.use(router_2.allowedMethods());
```
ようやく`koa-router`の使い方がわかりました!!ネクストステップです!!

##### 3. module.exportsしてみる
すみません、ここからkoa-routerと直接関係のない内容もちらほらあります...
やりたいことは、app.jsと同じフォルダ配下にindex.jsなるファイルを作成し、そこで設定したルーティングをapp.jsに読み込ませて利用したいという感じです。とてもわかりやすく記事にされてる方が多くいらっしゃるのでプログラムだけさらりと...

```javascript
//app.js
const Koa = require('koa');
const Router = require('koa-router');
//読込みしたいファイル名を記述する('.js'は不要)
const user = require('./index')

const koa = new Koa();
const router = new Router();


router.get('/test', (ctx, next) => {
    console.log('using router', ctx.method, ctx.url);
    ctx.body = 'Hello World!!';
});

router.get('/test2', (ctx, next) => {
    console.log('using router!!', ctx.method, ctx.url);
    ctx.body = 'Hello World!!';
});


koa.use(router.routes());
koa.use(router.allowedMethods());

koa.use(user.routes())


koa.listen(3000, () => {
    console.log('Server started!!');
});



//index.js
const Router = require('koa-router');
const router = new Router();

router.get('/user', (ctx, next) => {
    console.log(ctx.method, ctx.url);
    ctx.body = 'user route!!';
});


module.exports = router;
```
一つだけ備忘のために補足しておくと、`module.exports`にはなんでもかんでも指定できるわけではありません。上記`index.js`では、`router`の他にも`Router`もmodule.exportsとして指定することができます（意味がないのでやりませんが...）。

##### 3. DBで取得した結果を返す
いよいよDBを関わらせます。
`async/await`もちゃっかり出てきます。
MongoDBにはこれらのデータがあるとします。

```bash
~]$ mongo
MongoDB shell version v4.0.3
connecting to: mongodb://127.0.0.1:27017
...

> show dbs
...
...
testdb  0.000GB
> use testdb
switched to db testdb
> show collections
sample
> db.sample.find()
{ "_id" : ObjectId("5bd990d4e87b2960d233577f"), "field_a" : "りんご" }
{ "_id" : ObjectId("5bd990d4e87b2960d2335780"), "field_a" : "いちご" }
```
app.jsと同じフォルダ配下にDB接続用のモジュールファイル（db.js）を作成します

```javascript:db.js
const mongoose = require('mongoose');

const host = '127.0.0.1:27017'
const db = 'testdb'

mongoose.connect(`mongodb://${host}/${db}`, { useNewUrlParser: true });

const schema = new mongoose.Schema({
    field_a: String
});

'mongooseは3つ目の引数名のコレクションを処理対象として認識します'
'（デフォルトは一つ目の引数の頭小文字＋複数形）'
module.exports = mongoose.model('sample', schema, 'sample');
```
app.jsはこんな感じです。

```javascript:app.js
const Koa = require('koa');
const Router = require('koa-router');
//const user = require('./index');
const db = require('./db');

const koa = new Koa();
const router = new Router();

router.get('/test', (ctx, next) => {
    console.log('using router', ctx.method, ctx.url);
    ctx.body = 'Hello World!!';
});

router.get('/test2', (ctx, next) => {
    console.log('using router!!', ctx.method, ctx.url);
    ctx.body = 'Hello World!!';
});

router.get('/data', async (ctx, next) => {
    console.log('search data!!', ctx.method, ctx.url);
    const data = await db.findOne({'field_a': 'りんご'});
    ctx.body = data;
    console.log(data);
    return next();
})

koa.use(router.routes());
koa.use(router.allowedMethods());


koa.listen(3000, () => {
    console.log('Server started!!');
});
```
実行し、http://.../dataにアクセスすると、MongoDBに登録してあるデータがそのまま表示されます。
コンソールログはこんな感じに表示されます。

```bash
~]$ node app.js
Server started!!
search data!! GET /data
{ _id: 5bd990d4e87b2960d233577f, field_a: 'りんご' }
```
スッキリ。


###　おまけ
##### koa-routerの`allowedMethods`ってなん？
さりげなく書いていた
> koa.use(router.allowedMethods());

ですが、Gitにちゃんと答えが書かれていました。
例えば、`http://.../test`のアクセスに対しpostのルーティングだけを設定しする、こんな感じのプログラムを書きます。

```javascript:app.js
const Koa = require('koa');
const Router = require('koa-router');

const koa = new Koa();
const router = new Router();

router.post('/test', (ctx, next) => {
    console.log('using router', ctx.method, ctx.url);
    ctx.body = 'Hello World!!';
});

koa.use(router.routes());
//koa.use(router.allowedMethods());

koa.listen(3000, () => {
    console.log('Server started!!');
});
```
実行してアクセスしてみると、コンソールログには何も出力されないです。
Postしか定義されていないルートに対してGetでリクエストがやってきたので、Webサーバとしては405エラーを返したいところですが。
むむっ。コメントを外して実行し、アクセスしてみるとWeb上に`Method Not Allowed`が表示されます。
コンソールへ出力したいなど、独自で挙動を指定したいときは別途`methodNotAllowed`をkeyとしたvalue値に関数で書いてあげると良いです。
ちょっと長くなりそうなのでまた別でまとめます...

ほんの少しだけ、Koaさんのことを理解できたような気がします。ぽっ