最近はlambdaをTypeScript
で書いている僕です。
api gatewayから受け取った値にバリデーションする際にAjvを使ってみたのですが、大変便利だったのでメモしておきます。
import Ajv, {JSONSchemaType} from "ajv"
const ajv = new Ajv()
interface MyData {
foo: number
bar?: string
}
const schema: JSONSchemaType<MyData> = {
type: "object",
properties: {
foo: {type: "integer"},
bar: {type: "string", nullable: true}
},
required: ["foo"],
additionalProperties: false
}
// validate is a type guard for MyData - type is inferred from schema type
const validate = ajv.compile(schema)
// or, if you did not use type annotation for the schema,
// type parameter can be used to make it type guard:
// const validate = ajv.compile<MyData>(schema)
const data = {
foo: 1,
bar: "abc"
}
if (validate(data)) {
// data is MyData here
console.log(data.foo)
} else {
console.log(validate.errors)
}
>> 1
コードとドキュメントを見れば、だいぶ簡単にバリデーションが実装できることがわかると思います。
試しにエラーの場合はどうなるか見てみます。場合はrequired: ["foo"]
になっているのでこれをちょっと変えて。わざとエラーを発生させます。
const data = {
bar: "abc"
}
そうすると以下のようにエラーを教えてくれます。
[
{
instancePath: '',
schemaPath: '#/required',
keyword: 'required',
params: { missingProperty: 'foo' },
message: "must have required property 'foo'"
}
]
emailなどのバリデーションをしたい場合はFormat validationを使用します。
version 7 Ajvからajv-formatsを使用するようになっていますので、古い記事などにはお気をつけてください。
新しい使い方はプラグインを追加することで使えるようになります。
import Ajv from "ajv"
import addFormats from "ajv-formats"
const ajv = new Ajv()
addFormats(ajv)
試しに先ほどコードでfoo
をemailにしてバリデーションができているかどうか確認してみます。プロパティにformat
を追加するだけです。
全体のコードはこうなります。
import Ajv, {JSONSchemaType} from "ajv";
import addFormats from "ajv-formats";
const ajv = new Ajv();
addFormats(ajv);
interface MyData {
foo: string;
bar?: string;
}
const schema: JSONSchemaType<MyData> = {
type: "object",
properties: {
foo: {type: "string", format: "email"},
bar: {type: "string", nullable: true}
},
required: ["foo"],
additionalProperties: false
};
const validate = ajv.compile(schema);
const data = {
foo: "examplxample.com",
bar: "abc"
};
if (validate(data)) {
// data is MyData here
console.log(data.foo);
} else {
console.log(validate.errors);
}
プロパティでemailをバリデーションするようにしています。
properties: {
foo: {type: "string", format: "email"},
bar: {type: "string", nullable: true}
},
上記のコードは試しにわざとエラーを出してます。
[
{
instancePath: '/foo',
schemaPath: '#/properties/foo/format',
keyword: 'format',
params: { format: 'email' },
message: 'must match format "email"'
}
]
must match format "email"
となってますね! 成功です。これは大変便利です。lambaの開発が捗りそう。