express-validatorでvalidationしてみた。


やったこと

前回はServerless FrameworkをつかってAPI Gateway + LambdaでAPIを作ってみました。
https://qiita.com/Ntakato/items/d0778ecc03896a0ae196

ただ、validationくらいはできるようにしておきたい
そこで、今回はexpress-validatorを使ってvalidationできるようにしました。

express-validator

express-validator is a set of express.js middlewares that wraps validator.js validator and sanitizer functions.

やってみる

getting startをのぞいてみると

// ...rest of the initial code omitted for simplicity.
const { body, validationResult } = require('express-validator');

app.post(
  '/user',
  // username must be an email
  body('username').isEmail(),
  // password must be at least 5 chars long
  body('password').isLength({ min: 5 }),
  (req, res) => {
    // Finds the validation errors in this request and wraps them in an object with handy functions
    const errors = validationResult(req);
    if (!errors.isEmpty()) {
      return res.status(400).json({ errors: errors.array() });
    }

    User.create({
      username: req.body.username,
      password: req.body.password,
    }).then(user => res.json(user));
  },
);

なるほど、APIの処理本体に入る前にmiddlewaresをかませてvalidationしていますね。

body('username').isEmail()

でusernameがemailなのかをチェックして、emailじゃなかったら

const errors = validationResult(req);

でerrorsにerrorが入って、400エラーにしていますね。

ただ、実用的にはこのような感じでvalidatorをrouterに書いてしまうのは見通しがよくなさそうです。
bodyにvalidationするものが多かったりしたら大変なことになりそうです。

そこで、ここら辺のvalidatorは別ファイルに定義しておいて使うようにしたいなーと思いました。

ということで、以下のようなファイル構成にしてみました。

.
├── app.js
├── local-app.js
├── router.js
├── routes
└── validator.js

コード全体はGitHubに上げておきますが、大事なところは以下

// router.js

const express = require('express')
const router = express.Router()
const validator = require('./validator')

router.get('/v1/fun2', (req, res) => {
    res.json({ message: 'Function2!' })
})
router.get('/v1/fun2/user/:id', validator.userId, (req, res) => {
    const { id } = req.params
    const users = {
        'user1': { name: 'Bob', age: 23 },
        'user2': { name: 'Alice', age: 20 },
    }
    res.json({ ...users[id] })
})

module.exports = router

// validator.js

const { param, validationResult } = require('express-validator')

const badRequestErrorHandling = (req, res, next) => {
    const errors = validationResult(req);
    if (!errors.isEmpty()) {
        return res.status(400).json({ errors: errors.array() });
    }
    next()
}

const userId = [
    [
        param('id').isString(),
        param('id').isLength({ min: 5, max: 5 })
    ],
    badRequestErrorHandling
]

module.exports = {
    userId
}

これで、ローカル実行で試してみます。

まず、validationがOKな場合

$ curl localhost:3000/v1/fun2/user/user1
{"name":"Bob","age":23}

OKです。

つぎにvalidationがNGの場合

$ curl -i localhost:3000/v1/fun2/user/user11
HTTP/1.1 400 Bad Request
X-Powered-By: Express
Content-Type: application/json; charset=utf-8
Content-Length: 86
ETag: ******
Date: Sat, 30 Jan 2021 08:58:02 GMT
Connection: keep-alive

{"errors":[{"value":"user11","msg":"Invalid value","param":"id","location":"params"}]}

ちゃんと400エラーになってますね。

これでvalidationもできるようになりました。