| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | |||||
| 3 | 4 | 5 | 6 | 7 | 8 | 9 |
| 10 | 11 | 12 | 13 | 14 | 15 | 16 |
| 17 | 18 | 19 | 20 | 21 | 22 | 23 |
| 24 | 25 | 26 | 27 | 28 | 29 | 30 |
| 31 |
- vim
- 이미지
- glm-ocr
- Vite
- jsonl
- Webpack
- ndjson
- yaml
- Typescript
- Let's Encrypt
- vscode
- Thinking Mode
- Java
- json schema
- podman compose
- Ollama
- qwen3-coder-next
- k3s
- Docker Compose
- .dockerignore
- getting started
- PowerShell
- cli
- io
- RandomAccessFile
- json
- tauri
- docker
- podman
- curl
- Today
- Total
워로디스
JSON Schema 정리 본문
1. 한 줄 정의
JSON Schema는 JSON 데이터가 가져야 할 구조, 타입, 필수 필드, 값의 제약, 조합 규칙, 참조 관계, 문서화 메타데이터 등을 선언적으로 표현하는 스키마 언어입니다. 공식 명세는 JSON Schema를 “JSON 데이터의 구조를 정의하기 위한 JSON media type”으로 설명하며, 검증뿐 아니라 문서화, 하이퍼링크 탐색, 상호작용 제어까지 의도 범위에 포함합니다. (json-schema.org)
2. 먼저 구분해야 하는 층위
JSON Schema를 정확히 이해하려면 다음 층위를 섞지 않는 것이 중요합니다.
| 층위 | 설명 | 예 |
|---|---|---|
| 데이터 표현 형식 | 데이터가 파일에 쓰이는 문법 | JSON, YAML |
| 데이터 모델 | 값의 논리적 구조 | object, array, string, number, boolean, null |
| 스키마 언어 | 데이터 모델을 제약하는 언어 | JSON Schema |
| 스키마 표현 문법 | 스키마 자체를 어떤 문법으로 쓸지 | JSON으로 쓴 JSON Schema, YAML로 쓴 JSON Schema |
| 메타스키마 | 스키마 문서 자체가 올바른지 검증하는 스키마 | https://json-schema.org/draft/2020-12/schema |
| Dialect | 어떤 JSON Schema 버전/어휘 집합을 쓰는지 | Draft 2020-12, Draft 2019-09 |
| 검증기 | 스키마를 적용해 데이터를 검증하는 구현체 | Ajv, python-jsonschema 등 |
| 상위 생태계 | JSON Schema를 이용하거나 변형해 쓰는 시스템 | OpenAPI, Kubernetes CRD, 설정 파일 검증 등 |
중요한 점은 JSON Schema라는 이름 때문에 반드시 .json 파일이어야 한다는 뜻은 아니라는 것입니다. 스키마 언어는 JSON Schema이지만, 그 스키마 문서를 YAML 문법으로 표현할 수도 있습니다. 다만 공식 JSON Schema 명세 자체는 JSON 문서를 기준으로 정의되어 있고, JSON Schema 문서는 application/schema+json 미디어 타입을 갖는 JSON 문서라고 설명합니다. (json-schema.org)
3. 표준성 및 버전
3.1 현재 주류 버전
현재 공식 JSON Schema 사이트에서 안내하는 최신 버전은 Draft 2020-12이며, 이전 버전은 Draft 2019-09입니다. 명세는 크게 Core와 Validation 두 부분으로 나뉩니다. Core는 식별자, 참조, dialect, vocabulary 같은 기반 메커니즘을 정의하고, Validation은 실제 검증 키워드를 정의합니다. (json-schema.org)
3.2 RFC/ISO 표준인가?
엄밀히 말하면 JSON Schema Draft 2020-12 문서는 IETF의 Internet-Draft 형태로 공개되었고, 해당 문서 자체에도 Internet-Draft는 작업 문서이며 일정 기간 후 만료될 수 있다고 명시되어 있습니다. 따라서 ISO 표준이나 최종 RFC라고 말하기보다는, 공개 명세이자 사실상 업계 표준이라고 보는 것이 정확합니다. (json-schema.org)
3.3 주요 버전 계열
실무에서 자주 만나는 버전은 다음과 같습니다.
| 버전 | 특징 |
|---|---|
| Draft-04 | 오래된 시스템에서 여전히 사용 |
| Draft-06 / Draft-07 | 광범위하게 지원되는 구버전 |
| Draft 2019-09 | $defs, unevaluatedProperties, vocabulary 개념 등이 본격화 |
| Draft 2020-12 | 현재 공식 최신 주류 버전, prefixItems, $dynamicRef, $dynamicAnchor 등 사용 |
Draft 2020-12는 Draft 2019-09 이후의 업데이트로, 배열/튜플 키워드 재설계, 동적 참조, contains와 unevaluatedItems의 관계 명확화, Unicode 정규식 기대사항 등을 포함합니다. (json-schema.org)
4. JSON Schema의 기본 모델
4.1 Instance
JSON Schema에서 검증 대상 데이터는 instance라고 부릅니다. 즉, 다음 JSON 데이터는 스키마가 검증할 instance입니다. 공식 명세는 JSON 문서에 스키마가 적용될 때 그 JSON 문서를 instance라고 부릅니다. (json-schema.org)
{
"id": 1,
"name": "payment-service",
"enabled": true
}
4.2 Schema
스키마는 instance가 만족해야 하는 조건을 선언합니다.
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"name": {
"type": "string"
},
"enabled": {
"type": "boolean"
}
},
"required": ["id", "name"]
}
4.3 Schema는 object 또는 boolean
JSON Schema 문서는 반드시 object 또는 boolean이어야 합니다. true는 모든 instance를 허용하는 스키마이고, false는 어떤 instance도 허용하지 않는 스키마입니다. (json-schema.org)
true
false
실무에서는 대부분 object 형태의 스키마를 작성합니다.
5. 가장 기본적인 예제
5.1 검증 대상 데이터
{
"serviceName": "billing",
"port": 8080,
"env": "prod",
"replicas": 3,
"tags": ["api", "internal"]
}
5.2 JSON Schema
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://example.com/schemas/service-config.schema.json",
"title": "ServiceConfig",
"description": "서비스 배포 설정",
"type": "object",
"properties": {
"serviceName": {
"type": "string",
"minLength": 1
},
"port": {
"type": "integer",
"minimum": 1,
"maximum": 65535
},
"env": {
"type": "string",
"enum": ["dev", "staging", "prod"]
},
"replicas": {
"type": "integer",
"minimum": 1
},
"tags": {
"type": "array",
"items": {
"type": "string"
},
"uniqueItems": true
}
},
"required": ["serviceName", "port", "env"],
"additionalProperties": false
}
이 스키마는 다음을 의미합니다.
| 필드 | 제약 |
|---|---|
serviceName |
문자열이며 최소 길이 1 |
port |
정수이며 1 이상 65535 이하 |
env |
"dev", "staging", "prod" 중 하나 |
replicas |
정수이며 1 이상 |
tags |
문자열 배열이며 중복 불가 |
serviceName, port, env |
필수 |
| 정의되지 않은 필드 | 허용하지 않음 |
6. 핵심 키워드 분류
JSON Schema 키워드는 개념적으로 여러 종류로 나뉩니다. 공식 Core 명세는 키워드를 크게 identifier, assertion, annotation, applicator, reserved location 등으로 설명합니다. (json-schema.org)
| 분류 | 역할 | 대표 키워드 |
|---|---|---|
| 식별자 | 스키마의 URI, dialect, anchor 지정 | $schema, $id, $anchor, $dynamicAnchor |
| 검증 assertion | instance가 조건을 만족하는지 판단 | type, enum, const, minimum, required |
| annotation | 검증 외의 설명/힌트 제공 | title, description, default, examples |
| applicator | 하위 스키마를 적용하고 결과를 조합 | properties, items, allOf, anyOf, $ref |
| reserved location | 재사용 위치나 확장 위치 확보 | $defs |
7. 타입 시스템
JSON Schema의 기본 타입은 다음과 같습니다.
| 타입 | 의미 | 예 |
|---|---|---|
null |
값 없음 | null |
boolean |
참/거짓 | true, false |
object |
key-value 객체 | { "a": 1 } |
array |
순서 있는 목록 | [1, 2, 3] |
number |
숫자 | 3.14, 10 |
integer |
소수부가 0인 숫자 | 1, 42 |
string |
문자열 | "hello" |
Validation 명세에 따르면 type은 문자열 또는 문자열 배열일 수 있고, 문자열 값은 "null", "boolean", "object", "array", "number", "string", 또는 "integer" 중 하나입니다. 여기서 "integer"는 JSON 데이터 모델의 별도 원시 타입이라기보다, 소수부가 0인 number를 가리키는 검증 vocabulary상의 타입입니다. (json-schema.org)
7.1 단일 타입
{
"type": "string"
}
7.2 여러 타입 허용
{
"type": ["string", "null"]
}
이는 “문자열이거나 null”이라는 뜻입니다. OpenAPI 3.0의 nullable: true 같은 표현보다 JSON Schema 본래 방식에 가깝습니다.
8. 공통 검증 키워드
8.1 type
값의 타입을 제한합니다.
{
"type": "object"
}
8.2 enum
값이 지정된 목록 중 하나인지 제한합니다.
{
"type": "string",
"enum": ["dev", "staging", "prod"]
}
Validation 명세에 따르면 enum 값은 배열이어야 하며, instance 값이 배열 요소 중 하나와 같으면 검증에 성공합니다. (json-schema.org)
8.3 const
값이 정확히 하나의 상수와 같은지 제한합니다.
{
"const": "prod"
}
const는 단일 값만 갖는 enum과 기능적으로 동일합니다. (json-schema.org)
9. 문자열 검증
| 키워드 | 의미 |
|---|---|
minLength |
최소 문자 수 |
maxLength |
최대 문자 수 |
pattern |
정규식 매칭 |
format |
이메일, URI, 날짜 등 의미적 형식 힌트 |
{
"type": "string",
"minLength": 3,
"maxLength": 50,
"pattern": "^[a-z][a-z0-9-]*$"
}
pattern은 정규식이 문자열 전체에 자동으로 고정되는 것이 아닙니다. 즉 ^와 $를 직접 써야 전체 문자열 매칭이 됩니다. JSON Schema 명세는 정규식이 암묵적으로 anchored 되지 않는다고 설명합니다. (json-schema.org)
9.1 format 주의점
{
"type": "string",
"format": "email"
}
format은 기본적으로 강한 검증 assertion이라기보다 annotation 성격이 강합니다. Draft 2020-12에서는 format-annotation vocabulary와 format-assertion vocabulary가 구분되며, 구현체가 assertion 검증을 하려면 별도 설정이나 vocabulary 지원이 필요할 수 있습니다. 명세도 semantic validation은 애플리케이션에서 수행하는 것이 권장되는 관행이라고 설명합니다. (json-schema.org)
실무 지침:
이메일/URI/date-time 같은 값에 format을 쓰되,
보안·결제·권한처럼 중요한 검증은 애플리케이션 로직에서도 재검증한다.
10. 숫자 검증
| 키워드 | 의미 |
|---|---|
minimum |
이상 |
exclusiveMinimum |
초과 |
maximum |
이하 |
exclusiveMaximum |
미만 |
multipleOf |
특정 수의 배수 |
{
"type": "integer",
"minimum": 1,
"maximum": 65535
}
{
"type": "number",
"exclusiveMinimum": 0
}
Validation 명세는 maximum과 minimum을 포함 경계로, exclusiveMaximum과 exclusiveMinimum을 배타 경계로 정의합니다. multipleOf는 0보다 큰 숫자여야 하며, instance를 그 값으로 나눴을 때 정수가 되면 유효합니다. (json-schema.org)
11. 객체 검증
객체 검증은 JSON Schema에서 가장 많이 쓰이는 영역입니다.
11.1 properties
객체의 각 필드별 스키마를 정의합니다.
{
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"name": {
"type": "string"
}
}
}
중요한 점: properties에 정의했다고 해서 필수가 되는 것은 아닙니다. 필수 여부는 required로 따로 지정합니다.
11.2 required
{
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"name": {
"type": "string"
}
},
"required": ["id", "name"]
}
required는 문자열 배열이어야 하고, 배열에 있는 모든 이름이 instance object의 property로 존재해야 합니다. 생략하면 빈 배열과 같은 효과입니다. (json-schema.org)
11.3 additionalProperties
정의되지 않은 속성을 허용할지 제어합니다.
{
"type": "object",
"properties": {
"id": {
"type": "integer"
}
},
"additionalProperties": false
}
위 스키마는 id 외의 속성을 허용하지 않습니다.
다음처럼 추가 속성의 타입을 제한할 수도 있습니다.
{
"type": "object",
"properties": {
"id": {
"type": "integer"
}
},
"additionalProperties": {
"type": "string"
}
}
이 경우 id 외의 추가 속성은 모두 문자열이어야 합니다.
11.4 patternProperties
속성 이름이 특정 정규식에 매칭될 때 적용할 스키마를 지정합니다.
{
"type": "object",
"patternProperties": {
"^x-": {
"type": "string"
}
}
}
예를 들어 x-trace-id, x-request-id 같은 확장 필드를 허용할 때 유용합니다.
11.5 propertyNames
객체의 property 이름 자체를 검증합니다.
{
"type": "object",
"propertyNames": {
"pattern": "^[a-zA-Z_][a-zA-Z0-9_]*$"
}
}
propertyNames의 값은 JSON Schema여야 하고, object instance의 모든 property 이름이 그 스키마를 만족해야 합니다. 이때 property 이름은 항상 문자열로 검사됩니다. (json-schema.org)
11.6 minProperties, maxProperties
{
"type": "object",
"minProperties": 1,
"maxProperties": 10
}
객체의 속성 개수를 제한합니다. (json-schema.org)
11.7 dependentRequired
특정 필드가 있으면 다른 필드도 있어야 하는 경우 사용합니다.
{
"type": "object",
"properties": {
"creditCard": {
"type": "string"
},
"billingAddress": {
"type": "string"
}
},
"dependentRequired": {
"creditCard": ["billingAddress"]
}
}
의미:
creditCard가 있으면 billingAddress도 반드시 있어야 한다.
Validation 명세는 dependentRequired를 “특정 property가 존재할 경우 요구되는 다른 property들”을 지정하는 키워드로 정의합니다. (json-schema.org)
11.8 dependentSchemas
특정 필드가 존재하면 객체 전체에 추가 스키마를 적용합니다.
{
"type": "object",
"properties": {
"kind": {
"type": "string"
},
"cardNumber": {
"type": "string"
}
},
"dependentSchemas": {
"cardNumber": {
"required": ["kind"],
"properties": {
"kind": {
"const": "card"
}
}
}
}
}
dependentSchemas는 특정 property가 instance에 있을 때 전체 instance가 해당 subschema를 만족해야 한다는 의미입니다. (json-schema.org)
12. 배열 검증
12.1 동일 타입 배열: items
{
"type": "array",
"items": {
"type": "string"
}
}
의미:
모든 배열 요소는 string이어야 한다.
12.2 튜플 형태 배열: prefixItems
Draft 2020-12에서는 위치별 tuple 검증에 prefixItems를 사용합니다.
{
"type": "array",
"prefixItems": [
{
"type": "string"
},
{
"type": "integer"
},
{
"type": "boolean"
}
],
"items": false
}
의미:
첫 번째 요소: string
두 번째 요소: integer
세 번째 요소: boolean
그 이후 요소: 허용하지 않음
Draft 2020-12에서 기존의 items / additionalItems 구조는 prefixItems / items 구조로 재설계되었습니다. (json-schema.org)
12.3 minItems, maxItems
{
"type": "array",
"minItems": 1,
"maxItems": 5
}
배열 길이를 제한합니다. (json-schema.org)
12.4 uniqueItems
{
"type": "array",
"uniqueItems": true
}
배열 요소의 중복을 금지합니다. uniqueItems가 true이면 모든 요소가 서로 유일해야 합니다. (json-schema.org)
12.5 contains, minContains, maxContains
{
"type": "array",
"contains": {
"type": "integer",
"minimum": 10
},
"minContains": 1,
"maxContains": 3
}
의미:
배열 안에 10 이상의 integer가 최소 1개, 최대 3개 있어야 한다.
minContains와 maxContains는 같은 schema object 안의 contains 결과와 함께 동작합니다. contains가 없으면 효과가 없습니다. (json-schema.org)
13. 조합 키워드
JSON Schema는 여러 스키마를 논리적으로 조합할 수 있습니다.
| 키워드 | 의미 |
|---|---|
allOf |
모든 subschema를 만족해야 함 |
anyOf |
하나 이상 만족하면 됨 |
oneOf |
정확히 하나만 만족해야 함 |
not |
해당 schema를 만족하면 안 됨 |
공식 Core 명세는 이 키워드들을 subschema의 boolean assertion 결과를 조합하는 논리 연산자에 대응한다고 설명합니다. (json-schema.org)
13.1 allOf
{
"allOf": [
{
"type": "string"
},
{
"minLength": 3
}
]
}
문자열이면서 길이가 3 이상이어야 합니다.
13.2 anyOf
{
"anyOf": [
{
"type": "string"
},
{
"type": "integer"
}
]
}
문자열 또는 정수면 됩니다.
13.3 oneOf
{
"oneOf": [
{
"type": "string"
},
{
"type": "integer"
}
]
}
정확히 하나의 스키마만 만족해야 합니다.
13.4 not
{
"not": {
"type": "null"
}
}
null이 아니어야 합니다.
14. 조건부 검증
14.1 if, then, else
{
"type": "object",
"properties": {
"type": {
"enum": ["card", "bank"]
},
"cardNumber": {
"type": "string"
},
"accountNumber": {
"type": "string"
}
},
"required": ["type"],
"if": {
"properties": {
"type": {
"const": "card"
}
}
},
"then": {
"required": ["cardNumber"]
},
"else": {
"required": ["accountNumber"]
}
}
의미:
type이 card이면 cardNumber가 필요하다.
그 외에는 accountNumber가 필요하다.
Core 명세에 따르면 if 자체의 검증 결과는 전체 검증 결과에 직접 영향을 주지 않고, then 또는 else 중 어떤 스키마를 평가할지 결정합니다. (json-schema.org)
15. 참조와 재사용
15.1 $defs
반복되는 스키마 조각을 $defs에 정의합니다.
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$defs": {
"positiveInteger": {
"type": "integer",
"exclusiveMinimum": 0
}
},
"type": "array",
"items": {
"$ref": "#/$defs/positiveInteger"
}
}
공식 Core 명세도 $defs 안에 positiveInteger를 정의하고 $ref로 참조하는 예제를 제시합니다. (json-schema.org)
15.2 $ref
$ref는 다른 스키마 위치를 참조합니다.
{
"$ref": "#/$defs/User"
}
외부 파일이나 URI도 참조할 수 있습니다.
{
"$ref": "https://example.com/schemas/user.schema.json"
}
15.3 $id
$id는 스키마 리소스의 URI와 참조 기준 URI를 설정합니다.
{
"$id": "https://example.com/schemas/user.schema.json",
"type": "object"
}
Core 명세는 root schema가 fragment 없는 absolute URI 형태의 $id를 갖는 것을 권장합니다. 또한 subschema에 $id가 있으면 그 subschema는 하나의 별도 schema resource가 됩니다. (json-schema.org)
15.4 $anchor
$anchor는 스키마 내부의 이름 있는 위치를 만듭니다.
{
"$id": "https://example.com/schemas/common.schema.json",
"$defs": {
"Email": {
"$anchor": "Email",
"type": "string",
"format": "email"
}
}
}
참조:
{
"$ref": "https://example.com/schemas/common.schema.json#Email"
}
15.5 $dynamicRef, $dynamicAnchor
Draft 2020-12에서는 동적 참조 기능인 $dynamicRef, $dynamicAnchor가 도입되어 이전의 $recursiveRef, $recursiveAnchor를 대체합니다. 재귀적이거나 확장 가능한 스키마 모델링에서 쓰입니다. (json-schema.org)
16. additionalProperties와 unevaluatedProperties
이 둘은 실무에서 자주 헷갈립니다.
16.1 additionalProperties
현재 schema object의 properties, patternProperties에서 잡히지 않은 property에 적용됩니다.
{
"type": "object",
"properties": {
"id": {
"type": "integer"
}
},
"additionalProperties": false
}
단순한 객체에서는 이것으로 충분합니다.
16.2 unevaluatedProperties
allOf, $ref, anyOf 같은 조합을 쓸 때는 additionalProperties가 기대와 다르게 동작할 수 있습니다. 이때 unevaluatedProperties가 유용합니다.
{
"allOf": [
{
"$ref": "#/$defs/BaseUser"
}
],
"properties": {
"role": {
"type": "string"
}
},
"unevaluatedProperties": false,
"$defs": {
"BaseUser": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"name": {
"type": "string"
}
},
"required": ["id", "name"]
}
}
}
unevaluatedProperties는 인접한 키워드와 subschema 평가 결과를 고려해, 성공적으로 평가되지 않은 property에만 적용됩니다. 공식 문서도 unevaluatedProperties가 subschema에 선언된 property를 인식할 수 있다는 점에서 additionalProperties와 다르다고 설명합니다. (json-schema.org)
Core 명세 역시 unevaluatedProperties가 properties, patternProperties, additionalProperties, 그리고 인접 applicator들의 annotation 결과에 따라 동작한다고 설명합니다. (json-schema.org)
16.3 실무 기준
단순 객체:
additionalProperties: false
allOf, anyOf, oneOf, $ref 조합이 많은 객체:
unevaluatedProperties: false
17. additionalItems 대신 prefixItems / items
Draft 2020-12 기준에서는 tuple 검증에 prefixItems를 사용합니다.
구버전 스타일:
{
"type": "array",
"items": [
{
"type": "string"
},
{
"type": "integer"
}
],
"additionalItems": false
}
Draft 2020-12 스타일:
{
"type": "array",
"prefixItems": [
{
"type": "string"
},
{
"type": "integer"
}
],
"items": false
}
Draft 2020-12에서는 items와 additionalItems가 prefixItems와 items로 재설계되었습니다. (json-schema.org)
18. Annotation 키워드
Annotation 키워드는 검증 자체보다 문서화, UI 생성, 코드 생성, API 문서 생성에 도움을 줍니다.
| 키워드 | 의미 |
|---|---|
title |
짧은 이름 |
description |
설명 |
default |
기본값 힌트 |
examples |
예시 값 |
deprecated |
폐기 예정 여부 |
readOnly |
읽기 전용 힌트 |
writeOnly |
쓰기 전용 힌트 |
$comment |
스키마 작성자용 주석 |
Validation 명세는 title, description, default, deprecated, readOnly, writeOnly, examples 등을 기본 메타데이터 annotation vocabulary로 정의합니다. (json-schema.org)
주의할 점:
default는 대개 “문서화 힌트”이지,
검증기가 자동으로 값을 채워 넣는다는 뜻이 아니다.
검증기가 default를 실제로 적용하는지는 구현체와 설정에 따라 다릅니다.
19. Content 관련 키워드
문자열 안에 다른 미디어 타입이나 인코딩된 데이터가 들어있는 경우 다음 키워드를 사용할 수 있습니다.
| 키워드 | 의미 |
|---|---|
contentEncoding |
문자열이 어떤 방식으로 인코딩되었는지 |
contentMediaType |
문자열 내용의 미디어 타입 |
contentSchema |
문자열 내부 내용을 해석한 뒤 적용할 스키마 |
예:
{
"type": "string",
"contentEncoding": "base64",
"contentMediaType": "image/png"
}
Validation 명세는 이 키워드들이 JSON 문자열 안에 인코딩된 비JSON 데이터나 미디어 문서를 설명하기 위한 annotation이라고 설명하며, 잘못된 string-encoded document가 있다고 해서 반드시 containing instance가 invalid가 되는 것은 아니라고 명시합니다. (json-schema.org)
20. Meta-schema, Dialect, Vocabulary
20.1 $schema
$schema는 이 스키마가 어떤 dialect를 따르는지 지정합니다.
{
"$schema": "https://json-schema.org/draft/2020-12/schema"
}
Core 명세는 $schema를 JSON Schema dialect identifier이자 해당 dialect의 schema를 설명하는 resource identifier로 정의합니다. $schema는 document root schema object에서 사용하는 것이 권장되며, 없을 경우 동작은 구현체에 따라 달라질 수 있습니다. (json-schema.org)
20.2 Meta-schema
Meta-schema는 스키마를 검증하는 스키마입니다.
예를 들어 다음 meta-schema는 Draft 2020-12 스키마 문서가 올바른지 검증합니다.
https://json-schema.org/draft/2020-12/schema
공식 문서는 meta-schema를 “다른 schema를 검증하는 schema”라고 설명하고, 최신 meta-schema가 2020-12라고 안내합니다. (json-schema.org)
20.3 Vocabulary
Vocabulary는 키워드들의 의미 묶음입니다.
예:
| Vocabulary | 포함 개념 |
|---|---|
| Core | $schema, $id, $ref, $defs 등 |
| Applicator | allOf, anyOf, properties, items 등 |
| Validation | type, enum, required, minimum 등 |
| Unevaluated | unevaluatedProperties, unevaluatedItems |
| Format | format |
| Content | contentEncoding, contentMediaType, contentSchema |
$vocabulary는 meta-schema에서 사용되며, 해당 dialect가 어떤 vocabulary를 요구하거나 선택적으로 지원하는지 나타냅니다. Core 명세는 $vocabulary가 meta-schema에서 사용되어 vocabulary를 식별하고, 구현체가 필수 vocabulary를 이해해야 schema를 처리할 수 있음을 나타낸다고 설명합니다. (json-schema.org)
21. YAML 데이터와 JSON Schema
21.1 결론
YAML 데이터를 JSON Schema로 검증할 수 있습니다.
다만 정확한 표현은 다음과 같습니다.
검증 대상 데이터: YAML
스키마 언어: JSON Schema
스키마 문서 표현: JSON 또는 YAML
검증 방식: YAML을 JSON 호환 데이터 모델로 파싱한 뒤 JSON Schema 적용
JSON Schema 명세는 원칙적으로 JSON 문서를 대상으로 정의되어 있지만, JSON Schema 데이터 모델에 따라 파싱 또는 처리될 수 있는 문서/메모리 구조는 JSON Schema로 해석될 수 있다고 설명합니다. (json-schema.org)
22. JSON Schema를 YAML로 표현하기
22.1 JSON으로 쓴 JSON Schema
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"name": {
"type": "string"
},
"port": {
"type": "integer",
"minimum": 1,
"maximum": 65535
}
},
"required": ["name", "port"],
"additionalProperties": false
}
22.2 YAML로 쓴 JSON Schema
$schema: "https://json-schema.org/draft/2020-12/schema"
type: object
properties:
name:
type: string
port:
type: integer
minimum: 1
maximum: 65535
required:
- name
- port
additionalProperties: false
위 두 스키마는 논리적으로 같은 JSON Schema입니다.
중요한 표현:
YAML Schema가 아니라,
YAML 문법으로 직렬화한 JSON Schema다.
즉, JSON Schema의 키워드인 type, properties, required, additionalProperties를 YAML 문법으로 쓴 것입니다.
23. YAML 데이터 검증 예제
23.1 검증 대상 YAML
name: payment-service
port: 8080
enabled: true
tags:
- api
- internal
23.2 YAML로 작성한 JSON Schema
$schema: "https://json-schema.org/draft/2020-12/schema"
$id: "https://example.com/schemas/service-config.schema.yaml"
title: ServiceConfig
type: object
properties:
name:
type: string
minLength: 1
port:
type: integer
minimum: 1
maximum: 65535
enabled:
type: boolean
tags:
type: array
items:
type: string
uniqueItems: true
required:
- name
- port
additionalProperties: false
23.3 검증 흐름
1. YAML 파일을 파싱한다.
2. YAML 값을 JSON 호환 데이터 구조로 변환한다.
3. JSON Schema validator에 schema와 instance를 넘긴다.
4. validator가 valid / errors를 반환한다.
JSON Schema 출력 명세는 가장 단순한 결과로 boolean valid를 포함할 수 있고, 추가 정보가 필요하면 errors 또는 annotations를 포함할 수 있다고 설명합니다. (json-schema.org)
24. YAML 명세의 “JSON Schema”와 JSON Schema 검증 언어는 다르다
여기서 용어 충돌이 있습니다.
YAML 1.2 명세에도 JSON Schema라는 말이 나옵니다. 하지만 이것은 우리가 지금 말하는 JSON Schema 검증 언어가 아니라, YAML parser가 tag를 해석하는 YAML recommended schema 중 하나입니다. YAML 명세는 YAML schema를 “tag 집합과 non-specific tag를 resolve하는 메커니즘”으로 설명합니다. (YAML)
즉 다음 둘은 다릅니다.
| 표현 | 의미 |
|---|---|
| JSON Schema | JSON/YAML 데이터를 검증하는 스키마 언어 |
| YAML 1.2의 JSON schema | YAML scalar/tag 해석 방식 중 하나 |
YAML 1.2의 Core schema는 YAML의 JSON schema를 확장해 같은 타입을 더 사람이 읽기 쉬운 방식으로 표현할 수 있게 한 recommended default schema입니다. (YAML)
25. YAML로 JSON Schema를 쓸 때 주의할 점
25.1 YAML 1.2 기준으로 파싱하는 것이 좋다
YAML 1.2에서는 true, false만 boolean으로 파싱되고, y, yes, on 같은 값은 문자열로 파싱됩니다. YAML 1.1 계열 파서에서는 이런 값들이 boolean으로 해석될 수 있어 스키마와 실제 값이 달라질 수 있습니다. (Spec YAML)
안전한 방식:
mode: "on"
answer: "yes"
25.2 JSON Schema 키워드 값은 JSON 호환 타입이어야 한다
예를 들어 다음은 좋습니다.
type: object
required:
- id
- name
하지만 YAML 고유 태그나 복잡한 key 구조를 쓰면 JSON Schema validator가 기대하는 JSON 호환 데이터 모델에서 벗어날 수 있습니다.
피해야 할 예:
someKey: !!set
? a
? b
JSON Schema validator는 보통 YAML의 고유 태그 의미를 이해하지 않습니다.
25.3 YAML mapping key는 문자열로 제한하는 것이 안전하다
YAML 명세상 mapping key는 임의 node가 될 수 있지만, JSON object의 key는 문자열입니다. YAML 명세도 mapping은 key/value node pair의 집합이며 YAML 자체는 key node에 추가 제한을 두지 않는다고 설명합니다. (YAML)
JSON Schema와 함께 쓸 YAML은 다음처럼 문자열 key만 쓰는 것이 안전합니다.
name: app
port: 8080
피해야 할 예:
? [a, b]
: value
25.4 anchor와 alias는 최종 파싱 결과를 확인해야 한다
YAML anchor와 alias는 문법적으로 편리하지만, validator에 전달되는 최종 데이터 구조가 JSON 호환인지 확인해야 합니다.
common: &common
retries: 3
timeout: 1000
serviceA:
<<: *common
name: a
일부 파서나 설정에서는 merge key 처리 방식이 다를 수 있습니다. YAML 1.2 변경 사항에서는 merge <<와 value = 특수 mapping key가 제거되었다고 설명합니다. (Spec YAML)
25.5 중복 key를 피한다
JSON object에서는 같은 key가 중복되면 의미가 불명확합니다. YAML 명세도 mapping key는 unique해야 한다고 설명합니다. (YAML)
피해야 할 예:
name: a
name: b
25.6 schema 파일 확장자는 관례일 뿐이다
다음은 모두 가능할 수 있습니다.
schema.json
schema.yaml
schema.yml
중요한 것은 파일 확장자가 아니라, 해당 파일을 파싱한 결과가 JSON Schema로 해석 가능한 구조인지입니다.
26. JSON Schema를 YAML로 쓸 때의 장단점
| 방식 | 장점 | 단점 |
|---|---|---|
| JSON으로 작성 | 공식 명세와 가장 직접적으로 일치, 도구 호환성 높음 | 주석 불가, 긴 구조가 장황함 |
| YAML로 작성 | 가독성 좋음, 주석 가능, 설정 파일과 자연스럽게 어울림 | YAML 파서 차이, boolean/null/anchor/merge key 주의 필요 |
실무 판단:
라이브러리/패키지 배포용 표준 스키마:
schema.json 권장
사내 설정 파일 검증, 사람이 자주 읽고 수정하는 스키마:
schema.yaml 가능
OpenAPI, Kubernetes, CI 설정처럼 YAML 생태계에 붙는 경우:
YAML로 표현된 JSON Schema 계열 문법이 흔함
27. OpenAPI와 JSON Schema
OpenAPI 3.1은 JSON Schema Draft 2020-12 기반의 dialect를 제공합니다. OpenAPI Initiative의 dialect 문서도 $schema로 Draft 2020-12 meta-schema를 지정하고, OpenAPI 3.1 Schema Object Dialect가 OpenAPI v3.1 Description 안의 schema를 설명하는 JSON Schema dialect라고 밝힙니다. (OpenAPI Initiative Publications)
즉 OpenAPI 3.1에서는 다음과 같은 schema object가 JSON Schema와 더 잘 정렬됩니다.
type: object
properties:
id:
type: integer
name:
type: string
required:
- id
- name
다만 OpenAPI에는 discriminator, xml, API 문서화 관련 확장 등 JSON Schema 순수 명세와는 다른 맥락의 요소도 있으므로, “OpenAPI Schema Object = 완전히 순수한 JSON Schema”라고 단순화하면 안 됩니다.
28. 대표 패턴
28.1 닫힌 객체
{
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"name": {
"type": "string"
}
},
"required": ["id", "name"],
"additionalProperties": false
}
28.2 확장 가능한 객체
{
"type": "object",
"properties": {
"id": {
"type": "integer"
}
},
"required": ["id"],
"patternProperties": {
"^x-": {
"type": "string"
}
},
"additionalProperties": false
}
의미:
id는 필수.
x-로 시작하는 확장 필드는 문자열이면 허용.
그 외 필드는 금지.
28.3 Nullable 값
{
"type": ["string", "null"]
}
28.4 문자열 enum
{
"type": "string",
"enum": ["pending", "running", "succeeded", "failed"]
}
28.5 discriminated union 비슷한 패턴
{
"oneOf": [
{
"type": "object",
"properties": {
"kind": {
"const": "email"
},
"email": {
"type": "string",
"format": "email"
}
},
"required": ["kind", "email"],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"kind": {
"const": "sms"
},
"phone": {
"type": "string"
}
},
"required": ["kind", "phone"],
"additionalProperties": false
}
]
}
29. 실무 작성 규칙
29.1 항상 $schema를 명시한다
{
"$schema": "https://json-schema.org/draft/2020-12/schema"
}
이렇게 해야 검증기가 어떤 dialect로 해석해야 하는지 알 수 있습니다. $schema가 없으면 구현체별 기본값에 의존하게 됩니다. Core 명세도 $schema가 없을 경우 동작은 implementation-defined라고 설명합니다. (json-schema.org)
29.2 외부 공개 스키마에는 $id를 붙인다
{
"$id": "https://example.com/schemas/user.schema.json"
}
$ref를 안정적으로 운용하려면 $id가 중요합니다.
29.3 required와 properties를 혼동하지 않는다
{
"properties": {
"name": {
"type": "string"
}
}
}
위 스키마는 name이 있을 경우 문자열이어야 한다는 뜻이지, name이 반드시 있어야 한다는 뜻이 아닙니다.
필수로 만들려면:
{
"required": ["name"]
}
29.4 닫힌 객체를 원하면 명시적으로 닫는다
{
"additionalProperties": false
}
조합 스키마를 많이 쓴다면:
{
"unevaluatedProperties": false
}
29.5 format에 과도하게 의존하지 않는다
{
"type": "string",
"format": "email"
}
format 검증은 구현체 설정에 따라 annotation에 그칠 수 있습니다. 중요한 도메인 검증은 애플리케이션 레이어에서도 수행합니다. (json-schema.org)
29.6 정규식은 명시적으로 anchor 처리한다
부분 매칭 허용:
{
"pattern": "abc"
}
전체 매칭:
{
"pattern": "^abc$"
}
29.7 스키마 자체도 검증한다
스키마 문서도 meta-schema로 검증해야 합니다.
schema file → meta-schema로 검증
data file → schema로 검증
29.8 버전 관리한다
스키마는 API contract와 유사합니다.
user.schema.v1.json
user.schema.v2.json
또는 $id에 버전을 포함합니다.
{
"$id": "https://example.com/schemas/user/v1/schema.json"
}
30. 자주 하는 실수
| 실수 | 문제 | 권장 방식 |
|---|---|---|
properties만 쓰고 required 생략 |
필수가 아님 | 필수 필드는 required에 추가 |
additionalProperties 기본값을 착각 |
기본적으로 추가 필드 허용 | 닫고 싶으면 false 명시 |
format을 강검증으로 믿음 |
validator 설정에 따라 검증 안 될 수 있음 | 앱 레이어 검증 병행 |
| Draft 버전 혼용 | prefixItems, unevaluatedProperties 등이 안 먹을 수 있음 |
$schema 명시 |
YAML에서 on, yes를 문자열로 기대 |
파서 버전에 따라 boolean 가능 | 문자열은 quote |
$ref 경로를 상대적으로 막 씀 |
base URI 혼란 | $id와 $defs 체계화 |
oneOf를 남용 |
여러 스키마가 동시에 match되어 실패 가능 | discriminant 필드와 const 사용 |
default가 값을 채운다고 기대 |
보통 annotation | 채우기는 별도 로직 |
31. 최소 템플릿
31.1 JSON 버전
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://example.com/schemas/example.schema.json",
"title": "Example",
"description": "Example schema",
"type": "object",
"properties": {},
"required": [],
"additionalProperties": false
}
31.2 YAML 버전
$schema: "https://json-schema.org/draft/2020-12/schema"
$id: "https://example.com/schemas/example.schema.yaml"
title: Example
description: Example schema
type: object
properties: {}
required: []
additionalProperties: false
32. 키워드 빠른 참조
| 목적 | 키워드 |
|---|---|
| 타입 제한 | type |
| 값 목록 제한 | enum |
| 단일 값 제한 | const |
| 숫자 범위 | minimum, maximum, exclusiveMinimum, exclusiveMaximum |
| 숫자 배수 | multipleOf |
| 문자열 길이 | minLength, maxLength |
| 문자열 패턴 | pattern |
| 의미적 형식 | format |
| 객체 필드 정의 | properties |
| 객체 필드명 패턴 | patternProperties |
| 필수 필드 | required |
| 추가 필드 제어 | additionalProperties |
| 조합 후 미평가 필드 제어 | unevaluatedProperties |
| 객체 property 이름 검증 | propertyNames |
| 객체 필드 의존성 | dependentRequired, dependentSchemas |
| 배열 요소 스키마 | items |
| 튜플 배열 | prefixItems |
| 배열 길이 | minItems, maxItems |
| 배열 중복 금지 | uniqueItems |
| 특정 요소 포함 | contains, minContains, maxContains |
| 조합 | allOf, anyOf, oneOf, not |
| 조건 | if, then, else |
| 재사용 정의 | $defs |
| 참조 | $ref |
| 스키마 식별 | $id, $anchor |
| dialect 지정 | $schema |
| 설명 | title, description, examples, default |
33. 요약
JSON Schema는 JSON 데이터 구조를 선언적으로 정의하고 검증하기 위한 공개 명세이자 사실상의 표준입니다. 현재 기준으로는 Draft 2020-12를 기본 선택지로 보는 것이 좋고, 스키마 문서에는 반드시 $schema를 명시하는 편이 안전합니다. JSON Schema는 JSON 문법으로 작성하는 것이 원형이지만, 같은 구조를 YAML 문법으로 표현한 JSON Schema도 실무에서 충분히 사용됩니다. 단, YAML로 쓸 때는 YAML 고유 타입 해석, anchor, merge key, 중복 key, 문자열/boolean 파싱 차이를 주의해야 합니다.
'정리 > 데이터직렬화형식' 카테고리의 다른 글
| JSON Schema 치트시트 (0) | 2026.05.03 |
|---|---|
| JSONL, NDJSON 정리 (0) | 2026.05.03 |
