본문으로 건너뛰기
jsonbeautifiers
한국어

JSON Schema 생성기

샘플에서 draft 2020-12 스키마를 생성하고, required도 실제에 맞게 잡습니다.

샘플 JSON
스키마

붙여 넣은 것은 여러분의 브라우저를 떠나지 않습니다. connect-src 허용 목록 덕분에 이는 약속이 아니라 브라우저가 강제하는 보장입니다. 직접 확인하기

샘플 페이로드에서 JSON Schema를 생성합니다. 기본은 draft 2020-12이고 2019-09와 draft-07도 고를 수 있습니다.

샘플 하나로 스키마를 만드는 건 추론이고, 이런 도구들이 조용히 거짓말을 하는 지점이 바로 추론입니다. 이 도구가 하는 모든 추측은 여러분에게 보고되며, 그중 가장 큰 것은 대부분의 생성기와 다르게 다룹니다.

required 문제

대부분의 생성기는 배열의 첫 요소를 읽고 그 키들을 형태로 삼습니다. 그러면 뒤쪽 레코드에 첫 요소에는 없던 선택 필드가 나타나는 순간 유효한 데이터를 거부하는 스키마가 나옵니다.

이 생성기는 모든 요소를 합칩니다. 전부에 있는 키는 required에 들어가고, 일부에만 있는 키는 properties에는 나오되 required에는 들어가지 않습니다. 바로 이 차이 하나가 페이로드를 한번 훑고 손으로 쓰는 대신 생성기를 쓰는 이유입니다.

나머지 추론도 전부 보고합니다

integer 대 number
관측된 값이 모두 정수였을 때만 그 필드를 integer로 잡습니다. 어디든 소수가 하나 있으면 그 필드 전체가 number가 됩니다.
null 가능 필드
문자열로도 null로도 관측된 필드는 "type": ["string", "null"]이 됩니다. 필드를 빼 버리지도, 그냥 "string"으로 두지도 않습니다.
format
관측된 값이 전부 맞아떨어질 때만 붙입니다. date-time, date, time, email, uuid, ipv4, uri가 대상입니다. 맞지 않는 값이 하나라도 있으면 주석은 빠집니다.
enum
단정하지 않고 제안만 하며, 작은 값 집합이 반복될 때만 그렇게 합니다. 기본은 꺼짐입니다. 샘플 하나에서 추론한 enum은 전부 보지 못한 도메인에 대한 추측이기 때문입니다.
안전하지 않은 정수
integer로 잡고 함께 보고합니다. JavaScript 파서 위에서 도는 검증기는 검증을 시작하기도 전에 이미 그 값을 잃었기 때문입니다.

format 키워드는 검증하지 않습니다

이걸 모르면 놀라게 되고, 깨진 검증을 그대로 배포하게 됩니다. draft 2019-09와 draft 2020-12에서 format은 기본적으로 단언이 아니라 "주석"입니다. format 단언을 명시적으로 켜지 않는 한, 대부분의 검증기는 "format": "email"로 표시된 필드에 "not-an-email"을 아무렇지 않게 받아들입니다.

강제하고 싶다면 format 옆에 명시적인 pattern을 두거나, 검증기를 단언 동작으로 설정하고 그 검증기가 실제로 지원하는지 확인하세요.

결과를 검증할 때의 주의

이 스키마를 가장 흔한 JavaScript 검증기인 Ajv로 가져간다면 진입점을 조심하세요. 기본 ajv export는 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에 빠져 있는 이유는?
적어도 하나의 샘플에서 그 필드가 없었기 때문입니다. 생성기가 유용한 사실을 알려 주고 있는 겁니다. 정말로 필수 필드라면 모든 레코드에 그 필드가 있는 샘플을 주거나, required에 직접 추가하세요.
여러 샘플에서 생성할 수 있나요?
있고, 그렇게 하는 편이 좋습니다. 샘플들을 배열에 담아서 그 배열을 붙여 넣으세요. 여러 레코드에 걸쳐 합치는 것이야말로 required와 null 허용을 정확하게 만드는 방법입니다.