概要
ある時、typescriptで作成する入力フォームのバリデーションをしていて困ったことになった。
入力した値を、どうしても文字列の状態で上限値チェックしなければならなくなった。
具体的には、unixtimeが上限を超えないかどうかをチェックしなければならないのだが、値は文字列の状態で受け取り、また文字列の状態でレスポンスしなければならない。
使用していたバリデーション用のライブラリがAjvで、色々と調べたら独自のバリデーションができることを見つけたので、備忘録として残しておく。
標準の文字列判定
普通に文字列判定をしたいだけであれば、以下で事足りる。
import Ajv from "Ajv"
const ajv = new Ajv()
// 検証スキーマを定義
const schema = {
type: 'object',
properties: {
timestamp: {
type: 'string',
},
},
};
const timestamp = "2147483647"
//const timestamp = 2147483647
// バリデーション関数を作成
const validate = ajv.compile(schema);
// バリデーションを実行
const valid = validate({timestamp});
if (!valid) {
console.log(validate.errors)
}else{
console.log({result: true});
}
実行結果、文字列の場合
{ result: true }
実行結果、数値型の場合
[
{
keyword: 'type',
dataPath: '.timestamp',
schemaPath: '#/properties/timestamp/type',
params: { type: 'string' },
message: 'should be string'
}
]
カスタムバリデーション
以下のように、 ajv.addFormat
で、独自の判定フォーマット「custom-timestamp」を定義する。
判定フォーマットは、properties内の「format」で指定する。
import Ajv from "Ajv"
const ajv = new Ajv()
ajv.addFormat('custom-timestamp', {
validate: (timestampString: String) => {
const timestampNumber = Number(timestampString)
return timestampNumber < 2147483648
}
})
// 検証スキーマを定義
const schema = {
type: 'object',
properties: {
timestamp: {
type: 'string',
format: 'custom-timestamp',
},
},
};
const timestamp: String = "2147483647"
// バリデーション関数を作成
const validate = ajv.compile(schema);
// バリデーションを実行
const valid = validate({timestamp});
if (!valid) {
console.log(validate.errors)
}else{
console.log({result: true});
}
実行結果、「"2147483647"(unixtime期間内)」の場合
{ result: true }
実行結果、「"2147483648"(unixtime期間外)」の場合
[
{
keyword: 'format',
dataPath: '.timestamp',
schemaPath: '#/properties/timestamp/format',
params: { format: 'custom-timestamp' },
message: 'should match format "custom-timestamp"'
}
]
他のバリデーションライブラリでも、似たようなことはできるかもしれない。
また、今回は数字を文字列のまま大小比較するという実装だったが、実際にはもっと複雑なロジックを記述することも可能なので、用途は広い。
以上。