Ajvをスタンドアロン化しCSP環境下で利用する流れ
JSON schemaに対応したバリデーターの1つにAjvがあります。
JavaScriptでjson形式のバリデーションを行う場面でよく使われますが、CSP(コンテンツセキュリティポリシー)制限がある環境下では以下の様なエラーで実行が拒否されます。
EvalError: Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: "script-src 'self' blob: filesystem:".
これはAjvがschemaをコンパイルする際にnew Function()
を行うからであり、これがCSP制限に引っかかりスクリプトの実行そのものが拒否される為です。
The content security policy for Chrome Apps restricts you from doing the following:
You can't use inline scripting in your Chrome App pages. The restriction bans both
<script>
blocks and event handlers(<button onclick="...">
).
You can't reference any external resources in any of your app files (except for video and audio resources). You can't embed external resources in an iframe.
You can't use string-to-JavaScript methods like eval() and new Function().
デフォルトでCSP制限に上手に対応しているバリデーターもありますが、AjvもCSP制限をサポートしており、スタンドアロン化することでCSP環境下でも使用することが可能です。
Ajvのスタンドアロン化
Ajvのissuesでは上記内容と同等のCSP制限に関した質問がいくつか見られるようで、初見だと詰まる方もいるかもしれませんが特段難しい作業が必要という訳ではありません。
要はコンパイルの際に行うnew Function()
がCSP環境下で制限に引っかかるのであれば、事前にコンパイル済みのスタンドアロン版を用意してしまえば良いという事です。
スタンドアロン化はCLI版のajv-cliを用いて生成が可能です。
インストール
グローバルにajv-cli
をインストールします。
npm install -g ajv-cli
スタンドアロン化
JSON schemaの内容を記述したファイルをschema.json
として用意します。
例)schema.jsonの記述例
{ "type": "object", "properties": { "foo": {"type": "integer"}, "bar": {"type": "string"} }, "required": ["foo"], "additionalProperties": false}
以下でコンパイルを行います。
ajv compile -s schema.json -o validate-schema.js
出力されたvalidate-schema.js
がスタンドアロン化されたバリデーターになります。
使用方法
一般的なAjvの使用方法が以下ですが、スタンドアロン版も基本的には同じ流れで使用可能です。
import Ajv from "ajv"
const ajv = new Ajv()
const schema = { type: "object", properties: { foo: {type: "integer"}, bar: {type: "string"} }, required: ["foo"], additionalProperties: false,}
const validate = ajv.compile(schema)const valid = validate(data)if (!valid) console.log(validate.errors)
以下がスタンドアロン版を使用した記述です。
すでにコンパイル済みなので記述は少なく非常にスッキリしています。
import standaloneValidate from 'validate-schema'
const valid = standaloneValidate(data)if (!valid) console.log(validate.errors)
スタンドアロン化したvalidate-schema.js
をimportし、バリデーションを行うjsonデータを引数に渡してあげるだけです。
スタンドアロン化はCLI以外にajv/dist/standalone
を読み込んだコード上でも行うことができます。頻繁にJSON schemaが変わる場合はfs
で更新するのも良さそうです。