JSON Schemaジェネレーター
サンプルからdraft 2020-12のスキーマを生成。requiredも実態に忠実です。
貼り付けたものがブラウザの外に出ることはありません。 connect-src の許可リストにより、これは約束ではなくブラウザによる保証になっています。 自分で確かめる
サンプルのペイロードからJSON Schemaを生成します。既定はdraft 2020-12で、2019-09とdraft-07も選べます。
1つのサンプルからスキーマを作るのは推論であり、この種のツールが静かに嘘をつくのはまさに推論の部分です。ここで行う推測はすべて報告し、そのうち最も大きなものについては、多くのジェネレーターとは違う扱いをしています。
required問題
多くのジェネレーターは配列の最初の要素だけを読み、そのキーを構造とみなします。その結果できるスキーマは、後ろのレコードに最初の要素になかった任意フィールドが現れた瞬間、正しいデータを拒否します。
このジェネレーターはすべての要素をマージします。全要素に存在するキーはrequiredに入り、一部にしか存在しないキーはpropertiesには載るがrequiredには入りません。この一点こそが、ペイロードをざっと見て手書きするのではなくジェネレーターを使う理由です。
ほかの推論も、すべて報告します
- integerとnumber
- 観測されたすべての値が整数だった場合にだけ、その項目をintegerとします。どこかに小数がひとつでもあれば、その項目全体がnumberになります。
- null許容の項目
- 文字列としてもnullとしても観測された項目は"type": ["string", "null"]になります。項目を落とすことも、単なる"string"にすることもしません。
- format
- 観測されたすべての値が一致したときにだけ出力します。date-time、date、time、email、uuid、ipv4、uriが対象です。一致しない値がひとつでもあれば注釈は付けません。
- enum
- 断定ではなく提案として扱い、しかも小さな値の集合が繰り返されている場合だけです。既定はオフです。1つのサンプルから推論したenumは、全体を見ていないドメインについての推測にすぎないからです。
- 安全でない整数
- integerとして型付けしたうえで報告します。JavaScriptのパーサー上で動くバリデーターは、検証を始める前にすでにその値を失っているからです。
formatキーワードは検証しません
これは多くの人を驚かせ、壊れた検証をそのまま本番に送り出します。draft 2019-09とdraft 2020-12において、formatは既定でアサーションではなく「注釈」です。formatのアサーションを明示的に有効にしないかぎり、"format": "email"と書かれた項目に対して、多くのバリデーターは"not-an-email"を平然と受け入れます。
強制したい場合は、formatの隣に明示的なpatternを添えるか、バリデーターをアサーション動作に設定したうえで、そのバリデーターが実際に対応しているか確認してください。
結果を検証するときの注意
このスキーマをJavaScriptで最も一般的なバリデーターであるAjvに持ち込む場合、エントリポイントに注意してください。既定のajvエクスポートはdraft-07しかサポートしていません。draft 2020-12にはajv/dist/2020が、2019-09にはajv/dist/2019が必要です。
ここを間違えると、prefixItemsを使った2020-12のスキーマがdraft-07の意味論で検証され、そこではprefixItemsは未知のキーワードとして無視されます。その結果、妥当でないデータに対してバリデーターが「妥当」と報告します。これはエラーよりたちが悪く、しかも簡単にやってしまえます。
How to do this in code
コードでの生成と検証。
js JavaScript、Ajv
import Ajv from "ajv"ではdraft-07のバリデーターになり、2020-12のキーワードを黙って無視します。
// The entry point matters. This is the 2020-12 one.
import Ajv2020 from 'ajv/dist/2020';
import addFormats from 'ajv-formats';
const ajv = new Ajv2020({ allErrors: true });
addFormats(ajv); // without this, "format" does nothing at all
const validate = ajv.compile(schema);
if (!validate(data)) console.error(validate.errors); py Python
from jsonschema import Draft202012Validator
validator = Draft202012Validator(schema)
for error in sorted(validator.iter_errors(data), key=lambda e: e.path):
print(list(error.path), error.message)
# Format checking is opt-in here too
from jsonschema import FormatChecker
Draft202012Validator(schema, format_checker=FormatChecker()).validate(data) go Go
import "github.com/santhosh-tekuri/jsonschema/v6"
c := jsonschema.NewCompiler()
sch, err := c.Compile("schema.json")
if err := sch.Validate(data); err != nil {
fmt.Println(err)
} よくある質問
- どのdraftを使うべきですか?
- 新規のものにはdraft 2020-12を。現行の公開draftであり、OpenAPI 3.1が足並みをそろえている先でもあります。古いツール群での対応が最も広いのは依然としてdraft-07です。なお2020-12という識別子はdraftが切られた時期を指すもので、そのURIの文書が最後に再公開されたのは2022年6月であり、それは新しいリリースではなく修正版です。
- ある項目がrequiredに入らないのはなぜですか?
- 少なくとも1つのサンプルでその項目が存在しなかったからです。それはジェネレーターが有用なことを教えてくれている状態です。本当に必須なら、全レコードにその項目があるサンプルを与えるか、手でrequiredに追加してください。
- 複数のサンプルから生成できますか?
- できますし、そうすべきです。サンプルを配列に入れて、その配列を貼り付けてください。多数のレコードにわたってマージすることこそが、requiredとnull許容性を正確にします。