Node.jsでJoiでパラメータのバリデーション
日付 タグ node.js カテゴリ node.js目次
Joiを利用してパラメータのバリデーションを行う
例えば、ユーザー登録におけるユーザー名、パスワードなどに何かしらの文字数の制約や禁則文字の条件をつけて、サーバーに渡ってきたパラメータがそれらの条件を満たしているのかのチェックはNode.jsでどうやるのだろうか?そこで便利なのがオブジェクトのバリデーション用のJoiである。
https://github.com/hapijs/joi - Joi
今回はこのJoiというパッケージを使ってバリデーションする方法について見ていく。
なお、今回作ったサンプルのソースコードは参照用としてGithubの以下に置いてある。 https://github.com/hugodeblog/node-joi
今回実装するJoiを利用したサンプル
いつもの通り、サンプルディレクトリを作って、そこでJoiパッケージをインストール。
$ mkdir node-joi
$ cd node-joi
$ npm install --save joi
この記事を書いている時点ではJoiのバージョンは17.3.0であった。
joi_test.mjs
import Joi from 'joi';
const schema = Joi.object().keys({
username: Joi.string().alphanum().min(6).max(16).required(),
email: Joi.string().email(),
password: Joi.string().regex(/^[a-zA-Z_0-9]{8,30}$/).required()
})
// ユーザー名が短すぎる
// emailが適当な文字列すぎる
const payload1 = {
username: 'me',
email: 'wrong_string',
password: '12345678'
}
// emailはなくてもOK
const payload2 = {
username: 'testisok',
password: '12345678'
}
// passwordに使用不可な文字
const payload3 = {
username: 'testisok',
password: '12345a_5AB*678'
}
console.log('-------------------------');
console.log('checking payload1 ......');
console.log('-------------------------');
var {error, value} = schema.validate(payload1, { abortEarly: false })
if(error){
console.log(error.details);
} else {
console.log(value);
}
console.log('-------------------------');
console.log('checking payload2 ......');
console.log('-------------------------');
var {error, value} = schema.validate(payload2, { abortEarly: false })
if(error){
console.log(error.details);
} else {
console.log(value);
}
console.log('-------------------------');
console.log('checking payload3 ......');
console.log('-------------------------');
var {error, value} = schema.validate(payload3, { abortEarly: false })
if(error){
console.log(error.details);
} else {
console.log(value);
}
では、ちょっとコードの作りを見ておく。
const schema = Joi.object().keys({ username: Joi.string().alphanum().min(6).max(16).required(), email: Joi.string().email(), password: Joi.string().regex(/^[a-zA-Z_0-9]{8,30}$/).required() })
Joi.object()
でインスタンスを生成してキーのセットを定義する。
keys()
中で制約スキーマを定義していくのだが、
ここでは、
- username
- 文字列(アルファベット、数字)で最低6文字以上、最大16文字でrequired()で必ず必要
- email
- 組み込みのemail()を利用してEmailアドレス形式である制約。required()がないので省略可
- password
- regexで正規表現を用いて[a-zA-Z_0-9]で8文字以上、30文字まで、required()で必ず必要
サンプルのデータを与えて
(WebサービスならGETに付加されたパラメータやPOSTされたパラメータ)
const payload1 = { username: 'me', email: 'wrong_string', password: '12345678' }
これに対してスキーマを用いてバリデーションをする。
var {error, value} = schema.validate(payload1, { abortEarly: false }) if(error){ console.log(error.details); } else { console.log(value); }
実際の動作挙動チェック
$ node joi_test.mjs
-------------------------
checking payload1 ......
-------------------------
[
{
message: '"username" length must be at least 6 characters long',
path: [ 'username' ],
type: 'string.min',
context: {
limit: 6,
value: 'me',
encoding: undefined,
label: 'username',
key: 'username'
}
},
{
message: '"email" must be a valid email',
path: [ 'email' ],
type: 'string.email',
context: {
value: 'invalid_string',
invalids: [Array],
label: 'email',
key: 'email'
}
}
]
-------------------------
checking payload2 ......
-------------------------
{ username: 'testisok', password: '12345678' }
-------------------------
checking payload3 ......
-------------------------
[
{
message: '"password" with value "12345a_5AB*678" fails to match the required pattern: /^[a-zA-Z_0-9]{8,30}$/',
path: [ 'password' ],
type: 'string.pattern.base',
context: {
name: undefined,
regex: /^[a-zA-Z_0-9]{8,30}$/,
value: '12345a_5AB*678',
label: 'password',
key: 'password'
}
}
]
- payload1
- usernameとpasswordがスキーマの制約を満たしていないのでエラー
- payload2
- emailが与えられていないがemailは必須ではなくusernameとpasswordはスキーマの制約を満たしている
- payload3
- passwordにスキーマの制約に合っていない文字が含まれる
以上、Joiを使った値のバリデーションの簡単な使い方を見てきた。 あとは、これをGETに付加されたパラメータやPOSTのパラメータに適用していけば良いだろう。
今回passwordには簡単な正規表現で指定した制約のみを定義したが、より実用的にはパスワードにはもっと複雑なルールを課していくことになるだろう。