TypeScript(Node.js)のバリデーションライブラリ「Ajv」を使ってみた

2020.04.07

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

Ajv(Another JSON Schema Validator)はNode.jsとブラウザ用のバリデーションライブラリです。事前に定義した検証スキーマでデータのバリデーションを行います。また、バリデーションエラーの内容はerrorsプロパティに格納され、バリデーション後に取得することができます。

基本的な使い方

Ajvのインストールとバリデーションの方法を説明します。

インストール

npm(Node package manager)でインストールします。なお、型情報も組み込まれているため@types/ajvは必要ありません。

npm install ajv

バリデーションを実行

検証スキーマと検証データを定義してバリデーションを実行してみます。

import Ajv from 'ajv';

// インスタンスを作成
const ajv = new Ajv();

// 検証スキーマを定義
const schema = {
  required: ['name', 'email'],
  type: 'object',
  properties: {
    name: {
      type: 'string',
    },
    email: {
      type: 'string',
      format: 'email',
      maxLength: 50,
    },
    age: {
      type: 'integer',
    },
  },
};

// 検証データを定義
const data = {
  name: '田中太郎',
  email: 'test',
  age: 26,
};

// バリデーション関数を作成
const validate = ajv.compile(schema);

// バリデーションを実行
const valid = validate(data);

if (!valid) {
  // バリデーションエラー
  console.log(validate.errors);
}

次のエラーがコンソールに出力されます。

[
  {
    keyword: 'format',
    dataPath: '.email',
    schemaPath: '#/properties/email/format',
    params: { format: 'email' },
    message: 'should match format "email"'
  }
]

バリデーションの種類

良く使うバリデーションの種類を紹介します。

type

データが特定の型(number, integer, string, boolean, array, object, null)であることを検証します。また、配列でいずれかの型を検証することもできます。

const validate = ajv.compile({ type: 'string' });
validate('田中太郎'); // true
validate(100); // false

maxLength, minLength

文字列の長さを検証します。

const validate = ajv.compile({ maxLength: 4 });
validate('あいうえ'); // true
validate('あいうえお'); // false

maximum, minimum

数値の大きさを検証します。

const validate = ajv.compile({ maximum: 4 });
validate(4); // true
validate(5); // false

properties

オブジェクトプロパティの有効性を検証します。ただし、スキーマ定義したプロパティがオブジェクトに存在しない場合も、バリデーションの結果はtrueを返します。

const validate = ajv.compile({
  properties: {
    foo: { type: 'string' },
    bar: {
      type: 'number',
      minimum: 2,
    },
  },
});
validate({ foo: 'a', bar: 2 }); // true
validate({ foo: 'a' }); // true
validate({ foo: 'a', bar: 1 }); // false

required

オブジェクトに指定したプロパティが存在することを検証します。

const validate = ajv.compile({
  required: ['foo', 'bar'],
  properties: {
    foo: { type: 'string' },
    bar: {
      type: 'number',
      minimum: 2,
    },
  },
});
validate({ foo: 'a', bar: 2 }); // true
validate({ foo: 'a' }); // false
validate({ foo: 'a', bar: 1 }); // false

pattern

文字列を正規表現で検証します。文字列以外を指定した場合はtrueを返します。

const validate = ajv.compile({ pattern: '[abc]+' });
validate('abcd'); // true
validate(1); // true
validate(null); // true
validate('def'); // false
validate(''); // false

format

文字列を既存のフォーマットで検証します。文字列以外を指定した場合はtrueを返します。

const validate = ajv.compile({ format: 'date' });
validate('2020-04-07'); // true
validate(1); // true
validate(null); // true
validate('abc'); // false
validate(''); // false

フォーマット

バリデーションのformatで指定できる形式は次のとおりです。

項目 説明
date 日付(RFC3339に準拠) 2020-04-07
time 時間 23:59:59
date-time 日時 2020-04-07 23:59:59
uri 完全なURI file:///User/admin/Desktop/test.json
uri-reference 相対URIを含むURI Desktop/test.json
uri-template URIテンプレート(RFC6570に準拠) http://www.example.com/foo?number=100
url URLレコード(非推奨) http://example.com
email メールアドレス test@example.com
hostname ホスト名(RFC1034に準拠) example.com
ipv4 IPv4アドレス 192.168.0.1
ipv6 IPv6アドレス ABCD:EF01:2345:6789:ABCD:EF01:2345:6789
regex 正規表現 [abc]+
uuid 一意の識別子(RFC4122に準拠) 817dc001-06ef-4400-a85b-116015cbb7b7
json-pointer JSON pointer(RFC6901に準拠) /foo
relative-json-pointer JSON Resolve pointer

まとめ

Pythonで開発をしていた際には、Cerberusというバリデーションライブラリを導入していました。TypeScriptを採用した開発でも、Ajvで同じようにスキーマを定義してバリデーションができたのでとても使いやすく感じました。既にJSONデータが手元にある場合には、quicktypeというツールでスキーマを生成すると楽ができると思います。

参考資料