mongoose と Promise - Express MongoDBでjsonAPIサーバをつくる



##  mongooseについて
`MongoDB`と`Node.js`を接続するのに、今まで使ってきた`MongoDB`オフィシャルの`mongodb`ドライバーとスキーマを設定する`mongoose`ドライバーがありますが、ワタシ的にはオフィシャルの`mongodb`で十分かなと思ったのですが、一応アプリ側でルールが必要なときもあるかなと、記事を探していたら、少し古いですがいい記事が見つかりました。

[Node.js + Express 4.x + MongoDB(Mongoose)でRESTfulなjsonAPIサーバの作成を丁寧に解説する．+ テストクライアントを用いたAPIテストまで](https://qiita.com/shopetan/items/58a62a366aac4f5faa20)

内容はこれで、十分なのですが、`node.js`や`mongoose`が古いので、勉強がてら今風にコードもPromise風味で書き直してみました。
内容わかりやすいので、リンクを見てもらえればと思います。(笑)

### 使用ライブラリのバージョン

| パッケージ | バージョン |
| --- | --- |
| MongoDB | v4.0.4 |
| Node.js | v11.4.0 |

---

## ディレクトリツリー

```sh
.
├── app
│   ├── models
│   │   └── user.js
│   └── server.js
├── package.json
└── yarn.lock
```


### `package.json`

```json
{
  "name": "02",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "dependencies": {
    "body-parser": "^1.18.3",
    "express": "^4.16.4",
    "mongoose": "^5.4.1"
  }
}

```

### `user.js`

```js
const mongoose = require('mongoose')
const Schema = mongoose.Schema

const UserSchema = new Schema({
  twitter_id: { type: String, required: true, unique: true },
  name: String,
  age: Number
})

module.exports = mongoose.model('User', UserSchema)
```

### `server.js`

```js

const express = require('express')
const app = express()
const bodyParser = require('body-parser')
const port = process.env.PORT || 3000
const router = express.Router()
const mongoose = require('mongoose')
const User = require('./models/user')

// mongoose.Promise = global.Promise
mongoose.connect('mongodb://localhost:27017/jsonAPI', { useNewUrlParser: true, useCreateIndex: true })


app.use(bodyParser.urlencoded({ extended: true }))
app.use(bodyParser.json())
app.use('/api', router)

router.use((req, res, next) => {
  console.info('Something is happening.')
  next()
})
router.get('/', (req, res) => {
  res.json({ message: "Succesfully /api a test message."})
})
router.route('/users')
  .post(async(req, res) => {
    const user = new User()

    user.twitter_id = req.body.twitter_id
    user.name = req.body.name
    user.age = req.body.age

    await user.save()
      .then(result => {
        res.json({ message: "User created"})
      })
      .catch(err => {
        res.send(err)
        console.error(err)
      })
  })
  .get(async(req, res) => {
    await User.find({})
      .exec()
      .then(users => {
        res.json(users)
      })
      .catch(err => {
        res.send(err)
      })
  })

router.route('/users/:user_id')
  .get(async(req, res) => {
    await User.findById(req.params.user_id)
      .exec()
      .then(user => {
        res.json(user)
      })
      .catch(err => {
        res.send(err)
      })
  })
  .put(async(req, res) => {
    const result =  await User.findById(req.params.user_id)
      .then(user => {
        user.twitter_id = req.body.twitter_id
        user.name = req.body.name
        user.age = req.body.age
        return user
      })
      .catch(err => {
        res.send(err)
      })
    console.log('result', result)


      await result.save()
      .then(result => {
        res.json({ message: "User created"})
      })
      .catch(err => {
        res.send(err)
      })

  })
  .delete(async(req, res) => {
    await User.deleteOne({
      _id: req.params.user_id
    })
      .exec()
      .then(() => res.json({ message: "Successfully deleted"}))
      .catch(err => res.send(err))
  })

app.listen(port)
console.info('listen on port: ' + port)

```

簡単に説明しますと、`Promise`が使えるとして、返り値は`then`,`catch`で処理することになりますが、`Promsise`が使えると言うことは、`await`も使えると言うことなので、処理に`async`と`await`を挟んでいます、 `await`に後ろに処理がなければ、実際必要がないのですが、非同期処理をしていることを動機づけするために、書いたほうがいいでしょう。　あっても害になりませんし、後から処理を付け足したときに、バグを誘発するのを防げます。

`// mongoose.Promise = global.Promise` が必要かとつけていたんですが、なくても動きます。　問題がでたら、コメントを外せばいいかと思っていますが、ドライバー新しいので、defultで対応しているのかもしれません、この辺りは勉強不足ですみません。

`mongoose`で Promsiseの日本語の記事が少ないので、参考になればと思いupしました。