本文へスキップ
jsonbeautifiers
日本語

JSON Schemaジェネレーター

サンプルからdraft 2020-12のスキーマを生成。requiredも実態に忠実です。

サンプルJSON
スキーマ

貼り付けたものがブラウザの外に出ることはありません。 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許容性を正確にします。