Node.js express-validatorを使ってみた

expressフレームワークでexpress-validatorを使ってみたので、バリデーションする方法をまとめてみました。

# 環境

+ MacOSX (10.14)
+ Node.js (v10.15.2)
+ npm (6.4.1)
+ express (4.16.0)
+ express-validator (6.2.0)

# 準備
まずexpress-validatorをインストールします
`npm install express-validator`

# express-validator概要
できること
+ バリデーション
+ カスタムバリデーション
+ サニタイズ
+ カスタムサニタイズ
+ カスタムエラーメッセージ

# バリデーションサンプルコード(ノーマルな使用方法)
まず一番基本的な使い方は以下になります.(公式ドキュメントからコード抜粋)

```js:app.js
const { check, validationResult } = require('express-validator');
// 第二引数にバリデーションの記述
app.post('/user', [
  // checkメソッドを使用してバリデーションを実行
  check('username').isEmail(),
  check('password').isLength({ min: 5 })
], (req, res) => {
// バリデーションの結果にエラーがあるかのチェック
  const errors = validationResult(req);
  if (!errors.isEmpty()) {
    return res.status(422).json({ errors: errors.array() });
  }

  User.create({
    username: req.body.username,
    password: req.body.password
  }).then(user => res.json(user));
});  
```
1. ルーティングメソッド(今回はpostファンクション)の第2引数に配列でバリデーションの記述をする。
2. checkファンクションは全てのreqインスタンスの値から指定したフィールド名に一致するものをバリデーションします。  
bodyの値を対象にしたいならbodyファンクションをクエリパラメータならqueryファンクションを使います。そのほかに種類はあるので公式ドキュメントを見てください([公式ドキュメント](https://express-validator.github.io/docs/check-api.html))
3. .isEmail（）ファンクションで値がメールアドレスなのかをチェックしています。そのほかにもチェックするためのファンクションが[ここ](https://github.com/validatorjs/validator.js#validators)に記載されているので、見てください。
4. 第3引数のコールバック関数内に`validationResult`から値を取得し、エラーがあるのかをチェックします。  
エラーがあった場合はHTTPステータスコード422を指定して、レスポンスを返します。  

以上がノーマルなバリデーションでの使用方法です。
ただノーマルな使用方法では**ルーティング**の記述が読みずらくなってしまいます。
そこで次の使用方法が私のおすすめです。

#外部ファイル化してすっきりと
```js:ItemRegistValidator.js
const { check } = require('express-validator');

module.exports = [
  check('itemId').not().isEmpty().withMessage('必須項目です。').isInt().withMessage('アイテムIDは数値を入力してください'),
  check('itemName').not().isEmpty().withMessage('必須項目です。'),
];
```

```js:app.js
const { validationResult } = require('express-validator');

// 外部ファイル化したバリデーション読み込み
const ItemRegistValidator = require('../midleware/validators/itemRegistValidator');
// 第２引数で、バリデーションを実行
router.post('/', ItemRegistValidator, (req, res) => {
// バリデーションの結果にエラーがあるかのチェック
  const errors = validationResult(req);
  if (!errors.isEmpty()) {
    return res.status(422).json({ errors: errors.array() });
  }

  Item.create({
    itemId: req.body.itemId,
    itemName: req.body.itemName
  }).then(item => res.json(item));
});  
```
バリデーションの記述を外にすることで、だいぶすっきりしました。
バリデーション対象パラメータが多ければ多いほど、外部ファイルにするこの方法がおすすめです。  

1. `withMessage()`ファンクションはエラーメッセージを任意の内容に指定することができます。
2. その他に関してはノーマルな使用方法と同様です。'ItemRegistValidator.js'にて配列で、バリデーション処理の記述をし、ルーティングメソッドの第2引数で呼び出します。  

#バリデーションをカスタマイズ
```js
  // base64でエンコードされた画像ファイルの拡張子をバリデーション
  check('image').custom(image => {
    let extension = image.slice(image.indexOf('/') + 1, image.indexOf(';'));
    if (extension != 'png' && extension != 'jpeg') {
      throw new Error('画像の拡張子はpngまたはjpegを使用してください');
    }
    return true;
  })
```
validation.jsに用意されていないバリデーションをしたい時`custom`ファンクションを使いましょう。
1. customファンクションに引数でコールバック関数を指定し、バリデーションの処理をそのコールバック関数に記述します。
2. エラーであればErrorインスタンスをthrowし、問題なければtrueを返します。

#所感
express-validationを使用の仕方を記述いたしました。
上記の内容で、バリデーション処理を記述できるかと思います。
ここには書いていない点もありますので、[公式ドキュメント](https://express-validator.github.io/docs/)を見てください。
便利な関数が揃っているため非常に書きやすいと思います。