custom-format-validators について
z-schema で組み込みおよびカスタムの JSON Schema format バリデーターを設定する開発者向けスキルです。同期・非同期登録、ドラフトごとの動作、管理方法を扱います。
主な機能
- 01組み込み JSON Schema format
- 02同期・非同期フォーマットの登録
- 03グローバルおよびインスタンス単位の設定
- 04ドラフトごとの format アサーション設定
- 05フォーマットの一覧表示と解除
活用シーン
- 01アプリ固有の文字列形式の検証
- 02外部データに基づく値の確認
- 03組み込み形式チェックの無効化
- 04登録済み形式の確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ zaggino/ z-schema --skill custom-format-validatorsインストール後、Claude Code で/custom-format-validatorsを入力して読み込まれたか確認します。
詳細
z-schema のカスタムフォーマットバリデーター
JSON Schema の format は、基本的な型チェックに加えて、文字列(またはその他の値)を制約します。z-schema には組み込みバリデーターが含まれており、同期・非同期の両方に対応したカスタムバリデーターを登録できます。
組み込みフォーマット
z-schema には、標準 JSON Schema フォーマットすべてに対応するバリデーターが含まれています:
| フォーマット | 検証内容 |
|---|---|
date | RFC 3339 の完全日付(2024-01-15) |
date-time | RFC 3339 の日時(2024-01-15T09:30:00Z) |
time | RFC 3339 の時刻(09:30:00Z) |
email | RFC 5321 のメールアドレス |
idn-email | 国際化メールアドレス |
hostname | RFC 1123 のホスト名 |
host-name | hostname のエイリアス |
idn-hostname | 国際化ホスト名 |
ipv4 | IPv4 アドレス |
ipv6 | IPv6 アドレス |
uri | RFC 3986 URI |
strict-uri | 厳密に検証される RFC 3986 URI(strictUris: true の場合に uri と置き換わるものでもあります) |
uri-reference | URI または相対参照 |
uri-template | RFC 6570 URI テンプレート(完全な ABNF、正誤表 6937) |
iri | 国際化 URI |
iri-reference | 国際化 URI 参照 |
json-pointer | RFC 6901 JSON Pointer |
relative-json-pointer | 相対 JSON Pointer |
regex | ECMA-262 正規表現 |
duration | ISO 8601 期間 |
uuid | RFC 4122 UUID |
同期フォーマットの登録
フォーマットバリデーターは (input: unknown) => boolean という関数です。有効な場合は true、無効な場合は false を返します。該当しない型(例:入力が文字列でない場合)には true を返してください。z-schema はあらゆる値の型に対してフォーマットバリデーターを呼び出します。
グローバル登録(すべてのインスタンスで共有)
import ZSchema from 'z-schema';
ZSchema.registerFormat('postal-code', (value) => {
if (typeof value !== 'string') return true; // skip non-strings
return /^\d{5}(-\d{4})?$/.test(value);
});
インスタンスに限定した登録
const validator = ZSchema.create();
validator.registerFormat('postal-code', (value) => {
if (typeof value !== 'string') return true;
return /^\d{5}(-\d{4})?$/.test(value);
});
インスタンスのフォーマットは、同じ名前のグローバルフォーマットを上書きします。
作成時のオプションによる登録
const validator = ZSchema.create({
customFormats: {
'postal-code': (value) => typeof value === 'string' && /^\d{5}(-\d{4})?$/.test(value),
'always-valid': () => true,
'disable-email': null, // disable the built-in email validator
},
});
組み込みフォーマットまたはグローバル登録済みフォーマットを無効にするには、null を渡します。
非同期フォーマットの登録
Promise<boolean> を返します。バリデーターは { async: true } を指定して作成する必要があります。
const validator = ZSchema.create({ async: true });
validator.registerFormat('user-exists', async (value) => {
if (typeof value !== 'number') return true;
const user = await db.findUser(value);
return user != null;
});
// Validate (returns Promise)
try {
await validator.validate(data, schema);
} catch (err) {
console.log(err.details);
}
タイムアウト
非同期フォーマットバリデーターは asyncTimeout ミリ秒後にタイムアウトします(デフォルト:2000)。時間のかかる処理では、値を大きくしてください。
const validator = ZSchema.create({
async: true,
asyncTimeout: 10000, // 10 seconds
});
タイムアウトしたバリデーターは ASYNC_TIMEOUT エラーを生成します。
各ドラフトにおけるフォーマットアサーションの動作
JSON Schema の仕様では、新しいドラフトでformatの動作が変更されました。
| ドラフト | デフォルトの動作 | formatAssertions: trueの場合 |
|---|---|---|
| draft-04/06/07 | 常にアサーションを実行します(一致しない場合は失敗します) | 常にアサーションを実行します |
| draft-2019-09 | 常にアサーションを実行します(z-schema のデフォルト) | 語彙が有効になっていない限り、アノテーションのみです |
| draft-2020-12 | 常にアサーションを実行します(z-schema のデフォルト) | 語彙が有効になっていない限り、アノテーションのみです |
z-schema のデフォルトはformatAssertions: nullです(レガシー動作のため、常にアサーションを実行します)。新しいドラフトで仕様の語彙に応じた動作にするには、次のようにします。
const validator = ZSchema.create({ formatAssertions: true });
すべてのフォーマットアサーションを無効にする(アノテーションのみ)には、次のようにします。
const validator = ZSchema.create({ formatAssertions: false });
不明なフォーマット
デフォルトでは、draft-04/06/07で認識されないフォーマット名があると、z-schema はUNKNOWN_FORMATを報告します。新しいドラフト(2019-09、2020-12)では、不明なフォーマットは常に黙って無視されます。
古いドラフトで不明なフォーマットエラーを抑制するには、次のようにします。
const validator = ZSchema.create({ ignoreUnknownFormats: true });
フォーマットの登録解除
// Global
ZSchema.unregisterFormat('postal-code');
// Instance
validator.unregisterFormat('postal-code');
フォーマットの一覧表示
// List globally registered custom formats
const customFormats = ZSchema.getRegisteredFormats();
// List all supported formats (built-in + custom) on an instance
const allFormats = validator.getSupportedFormats();
// Check if a specific format is supported
const supported = validator.isFormatSupported('postal-code');
実際の使用例
電話番号の検証
ZSchema.registerFormat('phone', (value) => {
if (typeof value !== 'string') return true;
return /^\+?[1-9]\d{1,14}$/.test(value); // E.164 format
});
ISO 8601 日付(厳密)
ZSchema.registerFormat('iso-date', (value) => {
if (typeof value !== 'string') return true;
const d = new Date(value);
return !isNaN(d.getTime()) && value === d.toISOString().split('T')[0];
});
ビジネスルール:外部リストの値
const validator = ZSchema.create({ async: true });
validator.registerFormat('valid-country', async (value) => {
if (typeof value !== 'string') return true;
const countries = await fetchValidCountries();
return countries.includes(value.toUpperCase());
});
副作用:デフォルト値の事前入力
フォーマットバリデーターはオブジェクトを変更できます(注意して使用してください)。
ZSchema.registerFormat('fill-defaults', (obj) => {
if (typeof obj === 'object' && obj !== null) {
(obj as Record<string, unknown>).createdAt ??= new Date().toISOString();
}
return true;
});
スキーマの使用方法
{
"type": "object",
"properties": {
"phone": { "type": "string", "format": "phone" },
"country": { "type": "string", "format": "valid-country" },
"zipCode": { "type": "string", "format": "postal-code" }
}
}