7
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

express-validator を使ってみたポイント

Posted at

はじめに

以前、 Node.js + Express.js で Web API を開発した際、 入力チェックに express-validator を使いました。
express-validator は validator.js がベースになっており、 validation や sanitize ができる便利なモジュールですが、提供されている API は文字列に対する検証になるため、 JSON パラメータの型を明確にチェックしたい場合には少し注意が必要でした。
今回は使用した際のポイントなんかを自分の整理がてらメモとして残します。

環境

OS: macOS Mojave 10.14.6
Node.js: 10.16.3
Express.js: 4.16.1
express-validator: 6.2.0

Case1(GET & 桁チェック)

引数 必須
arg1
arg2 min:2 max:4
arg3 max:4
arg4 min:2
case1.js
const express = require('express');
const router = express.Router();
const {check, validationResult} = require('express-validator');

router.get('/', validateParam(), async (req, res) => {
    const errors = validationResult(req);
    if(!errors.isEmpty()) {
        res.status(400).end();
        return;
    }

    res.status(200).end();
});

function validateParam() {
	return [
		check('arg1')
			.exists({checkFalsy: true})
            .isString(),
        check('arg2')
            .optional({nullable: true})
            .isInt()
            .isLength({min: 2, max: 4}),
        check('arg3')
            .optional({nullable: true})
            .isInt()
            .isLength({min: undefined, max: 4}),
        check('arg4')
            .optional({nullable: true})
            .isInt()
            .isLength({min: 2, max: undefined})
    ];
}

module.exports = router;

OKな例

?arg1=hoge
?arg1=hoge&arg2=12
?arg1=hoge&arg2=1234
?arg1=hoge&arg3=12
?arg1=hoge&arg3=1
?arg1=hoge&arg3=1234
?arg1=hoge&arg4=12
?arg1=hoge&arg4=1234567890

NGな例

?arg1=hoge&arg2=1
?arg1=hoge&arg2=12345
?arg1=hoge&arg3=12345
?arg1=hoge&arg4=1

解説

GET メソッドを例に桁チェックを行います。
桁は isLength() を使用してチェックできます。
さらに、オプションで min (最小値)と max (最大値)が指定できます。
OKな例とNGな例で、オプションで指定した min と max の境界値が効いているのがわかります。

Case2(POST & 型チェック)

引数 必須
arg1 整数
arg2 文字列の整数
arg3 真偽値
case2.js
const express = require('express');
const router = express.Router();
const {check, validationResult} = require('express-validator');

router.post('/', validateParam(), async (req, res) => {
    const errors = validationResult(req);
    if(!errors.isEmpty()) {
        res.status(400).end();
        return;
    }

    res.status(200).end();
});

function validateParam() {
	return [
        check('arg1')
            .exists({nullable: true})
            .not().isString()
            .isInt(),
        check('arg2')
            .optional({nullable: true})
            .isString()
            .isInt(),
        check('arg3')
            .optional({nullable: true})
            .not().isString()
            .not().isInt()
            .isBoolean()
    ];
}

module.exports = router;

OKな例

{
    arg1: 1,
    arg2: '1'
}

{
    arg1: 1,
    arg3: true    
}

NGな例

{
    arg1: 1,
    arg2: 'a'
}

{
    arg1: 1,
    arg2: 1
}

{
    arg1: 1,
    arg3: 'true'
}

{
    arg1: 1,
    arg3: 1
}

解説

POST メソッドを例に型チェックを行います。
冒頭に触れている通り、 express-validator の API は文字列に対する検証なので、少し工夫をします。
arg1 は整数なので、 .not().isString().isInt() を組み合わせて文字列ではないかつ整数という指定になります。
arg2 のように文字列の整数に限定したい場合は、.isString().isInt() を組み合わせて文字列かつ整数という指定になります。
arg3 は真偽値ですが、文字列の 'false', 'true' や整数の 0, 1 が真偽値として判定されないようそれぞれ .not().isString().not().isInt() という指定をしています。ケースによっては上記を真偽値として判定したいという場合もあるので、その場合は適宜指定を外せばOKです。

Case3(POST & 条件付き必須)

引数 必須
arg1 真偽値
arg2 arg1=true の場合のみ必須 文字列
case3.js
const express = require('express');
const router = express.Router();
const {check, oneOf, validationResult} = require('express-validator');

router.post('/', validateParam(), async (req, res) => {
    const errors = validationResult(req);
    if(!errors.isEmpty()) {
        res.status(400).end();
        return;
    }

    res.status(200).end();
});

function validateParam() {
	return [
        check('arg1')
            .exists({checkNull: true})
            .not().isString()
            .not().isInt()
            .isBoolean(),
        check('arg2')
            .optional({nullable: true})
            .isString(),
        oneOf(
            [
                check('arg1')
                    .custom((value) => value === false),
                check('arg2')
                    .exists({checkNull: true})
            ]
        )
    ];
}

module.exports = router;

OKな例

{
    arg1: false
}

{
    arg1: true,
    arg2: 'hoge'
}

NGな例

{
    arg1: true
}

解説

POST メソッドを例に条件付き必須チェックを行います。
条件付き必須チェックを行う場合には oneOf() が使用できます。
oneOf() は Validation Chain の配列で、いずれか1つでも真であれば検証OK(=すべて偽だった場合に検証NG)となります。これを利用すると、 arg2 のarg1=true の場合のみ必須という条件は、arg1=falsearg2が必須どちらかが真という条件に置き換えることができます(もっとスマートなやり方があれば教えて下さい)。

まとめ

今回は簡単なサンプルを例にとって紹介しましたが、 express-validator のようなモジュールがあると、組み合わせでたいていの要件を満たすことができてとても便利です。
Web API で入力チェックはとても大切ですが、あまり時間をかけたくないところでもあります。また、実装者が複数いれば実装の粒度も変わりやすいので、実装者に依存しにくくなるというのも大きなメリットでしょうか。

今回、使用したコードはGitHubで公開しています。
https://github.com/ponko2bunbun/express-validator-sample

7
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?