はじめに
- Validationコードを手で書きたくなかった
- JSON schemaを手書きしたくなかった(typescriptの型定義を使ってほしい)
国内外たくさんやってることだけど、真似しても使うのに時間がかかった。
最小構成のコードを書く。
まず、Validationができてない状態とは?
index.ts
interface Cat {
name: string,
age: number
}
const catObj = JSON.parse('{"name":"tamago", "weight":2.0}');
const cat = catObj as Cat;
console.log(cat.age); //undefined (Catのageはオプショナルじゃないのに!)
さあ、validationしよう
- 実行前にtypescriptコードからtypescript-json-schemaでJSON schema(.json)を生成する
- 実行時にajvでJSON Schemaを読み込んで、JSONをvalidationする
1.実行前にtypescriptコードからtypescript-json-schemaでJSON schema(.json)を生成する
typescript-json-schemaをインストール
% npm install typescript-json-schema -g
typescriptコードからJSON schemaを生成
型情報が含まれるtypescriptファイル
cat.ts
interface Cat {
name: string,
age: number
}
export {Cat};
cat.tsのCat型のスキーマをCatSchema.jsonに吐き出す
(cat.tsのように単独ファイルにしていなくてもいい)
% typescript-json-schema --strictNullChecks true --noExtraProps true cat.ts Cat > CatSchema.json
--strictNullChecks Make values non-nullable by default. [boolean] [default: false]
--noExtraProps Disable additional properties in objects by default. [boolean] [default: false]
2. 実行時にajvでJSON Schemaを読み込んで、JSONをvalidationする
ajv他をインストール
% npm install ajv --save
% npm install @types/node --save-dev
% npm install @types/ajv --save-dev
コード全体
index.ts
import * as fs from 'fs'
import * as Ajv from 'ajv';
import {Cat} from './cat'
const myJSON = '{"name":"tamago", "weight":2.0}'
const catObj = JSON.parse(myJSON);
const ajv = new Ajv();
const catSchema = JSON.parse(fs.readFileSync('./CatSchema.json').toString());
const validate = ajv.compile(catSchema);
if(validate(catObj)){
console.log('validation ok');
//安心してasを使おう
const myCat = catObj as Cat;
}
else{
console.log('validation ng');
console.error(validate.errors);
}
実行
% ts-node index.ts
validation ng
[ { keyword: 'additionalProperties',
dataPath: '',
schemaPath: '#/additionalProperties',
params: { additionalProperty: 'weight' },
message: 'should NOT have additional properties' } ]
ts-node便利なのでよく使っています。
typescriptの型定義のオプショナルもちゃんと扱ってくれるようです。
まとめ
事前のJSON Schema生成はいるが、自動でvalidation環境が作れる。
丁寧な日本語メッセージを返したい場合は、ErrorObject型をアレコレしましょう。
Typescriptの標準機能で欲しい。