JSON Schema는 JSON 데이터 구조를 설명하고 검증하는 업계 표준입니다. API 요청 페이로드 강제·설정 파일 검증·폼 유효성 검사 로직 구축 등 어떤 경우에도 온라인 JSON Schema 검증기를 사용하면 라이브러리 설치나 테스트 하네스 없이 스키마와 샘플 데이터를 즉시 테스트할 수 있습니다.
JSON Schema란
JSON Schema는 JSON 문서에 주석을 달고 검증하기 위한 선언적 어휘입니다. 스키마 자체도 JSON(또는 YAML) 문서로, 데이터의 예상되는 형태·타입·제약 조건을 설명합니다.
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"required": ["id", "email", "role"],
"properties": {
"id": { "type": "integer", "minimum": 1 },
"email": { "type": "string", "format": "email" },
"role": { "type": "string", "enum": ["admin", "editor", "viewer"] },
"createdAt": { "type": "string", "format": "date-time" }
},
"additionalProperties": false
}
이 스키마는 검증할 JSON 객체에 세 개의 필수 필드가 있고, id가 양의 정수, email이 유효한 이메일 주소, role이 세 가지 허용된 값 중 하나임을 보장합니다.
JSON Schema 드래프트 버전
명세는 크게 발전해 왔습니다. 버전 전체 그림을 이해하면 스키마가 예상치 못하게 동작할 때의 혼란을 방지할 수 있습니다:
| 드래프트 | 출시 | 주요 추가 기능 |
|---|---|---|
| Draft-04 | 2013 | 코어 어휘, $ref, allOf/anyOf/oneOf |
| Draft-06 | 2017 | const, contains, propertyNames, readOnly |
| Draft-07 | 2019 | if/then/else, writeOnly, $comment |
| 2019-09 | 2019 | $defs, unevaluatedProperties, $anchor |
| 2020-12 | 2021 | Prefix items, $dynamicRef, 개선된 $ref |
항상 $schema로 드래프트를 선언하세요. 선언이 없으면 검증기가 다른 기본값을 적용할 수 있습니다. 현재 프로덕션 사용의 대부분은 draft-07 또는 2020-12입니다.
핵심 스키마 키워드
타입 제약
{ "type": "string" }
{ "type": "integer" }
{ "type": "number" }
{ "type": "boolean" }
{ "type": "null" }
{ "type": "array" }
{ "type": "object" }
// 여러 타입 허용:
{ "type": ["string", "null"] }
객체 제약
{
"type": "object",
"properties": {
"name": { "type": "string" },
"age": { "type": "integer", "minimum": 0 }
},
"required": ["name"],
"additionalProperties": false,
"minProperties": 1,
"maxProperties": 10
}
additionalProperties: false는 가장 효과적인 안전 제약입니다. properties에 나열되지 않은 모든 키를 거부하여 오타와 예상치 못한 필드를 감지합니다.
문자열 제약
{
"type": "string",
"minLength": 3,
"maxLength": 100,
"pattern": "^[a-z][a-z0-9_]*$",
"format": "email"
}
일반적인 format 값: email·uri·date·date-time·time·ipv4·ipv6·uuid. 참고: 형식 검증은 기본적으로 선택적입니다. 검증기에서 명시적으로 활성화해야 합니다.
배열 제약
{
"type": "array",
"items": { "type": "string" },
"minItems": 1,
"maxItems": 50,
"uniqueItems": true
}
draft 2020-12에서는 튜플 검증을 위해 items가 prefixItems로 이름이 변경되었습니다. 동질적인 배열에는 items, 위치 지정 튜플에는 prefixItems를 사용합니다.
숫자 제약
{
"type": "number",
"minimum": 0,
"maximum": 100,
"exclusiveMinimum": 0,
"multipleOf": 0.5
}
열거형과 const
// 허용된 값 중 하나:
{ "enum": ["draft", "published", "archived"] }
// 정확히 하나의 값(판별 유니온에 유용):
{ "const": "v2" }
조합 키워드
// 모든 서브스키마에 매칭되어야 함:
{ "allOf": [{ "type": "string" }, { "minLength": 1 }] }
// 최소 하나의 서브스키마에 매칭되어야 함:
{ "anyOf": [{ "type": "string" }, { "type": "number" }] }
// 정확히 하나의 서브스키마에 매칭되어야 함:
{ "oneOf": [
{ "type": "string", "format": "email" },
{ "type": "string", "format": "uri" }
] }
// 서브스키마에 매칭되지 않아야 함:
{ "not": { "type": "null" } }
조건부 검증(Draft-07 이상)
{
"if": { "properties": { "type": { "const": "company" } } },
"then": { "required": ["companyName", "taxId"] },
"else": { "required": ["firstName", "lastName"] }
}
이것은 JSON Schema에서 가장 강력한 기능 중 하나입니다. 다른 필드의 값에 따라 다른 필수 필드를 강제할 수 있습니다.
스키마 참조와 재사용
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$defs": {
"address": {
"type": "object",
"required": ["street", "city", "country"],
"properties": {
"street": { "type": "string" },
"city": { "type": "string" },
"country": { "type": "string", "minLength": 2, "maxLength": 2 }
}
}
},
"type": "object",
"properties": {
"billingAddress": { "$ref": "#/$defs/address" },
"shippingAddress": { "$ref": "#/$defs/address" }
}
}
$defs(이전 드래프트에서는 definitions)는 스키마를 DRY하게 유지합니다. $ref는 로컬(#/...)과 원격(https://...) 참조를 모두 지원합니다.
코드로 JSON Schema 검증하기
Node.js(AJV)
AJV는 가장 빠르고 널리 사용되는 JavaScript JSON Schema 검증기입니다:
npm install ajv ajv-formats
import Ajv from 'ajv';
import addFormats from 'ajv-formats';
const ajv = new Ajv({ allErrors: true });
addFormats(ajv);
const schema = {
type: 'object',
required: ['email', 'age'],
properties: {
email: { type: 'string', format: 'email' },
age: { type: 'integer', minimum: 18 },
},
additionalProperties: false,
};
const validate = ajv.compile(schema);
const data = { email: 'user@example.com', age: 25 };
if (validate(data)) {
console.log('Valid');
} else {
console.log('Errors:', validate.errors);
}
AJV는 스키마를 최적화된 JavaScript 함수로 컴파일하므로 매우 빠르고 핫 요청 경로에도 적합합니다.
Python(jsonschema)
pip install jsonschema
import jsonschema
from jsonschema import validate, ValidationError
schema = {
"type": "object",
"required": ["email", "age"],
"properties": {
"email": {"type": "string", "format": "email"},
"age": {"type": "integer", "minimum": 18},
},
"additionalProperties": False,
}
data = {"email": "user@example.com", "age": 25}
try:
validate(instance=data, schema=schema)
print("Valid")
except ValidationError as e:
print(f"Invalid: {e.message}")
print(f"Path: {list(e.absolute_path)}")
모든 오류(첫 번째만이 아닌)를 얻으려면 jsonschema.Draft202012Validator를 사용합니다:
from jsonschema import Draft202012Validator
validator = Draft202012Validator(schema)
errors = list(validator.iter_errors(data))
for error in errors:
print(f"{'.'.join(str(p) for p in error.path)}: {error.message}")
Go(santhosh-tekuri)
go get github.com/santhosh-tekuri/jsonschema/v6
package main
import (
"fmt"
"strings"
"github.com/santhosh-tekuri/jsonschema/v6"
)
func main() {
schemaJSON := `{
"type": "object",
"required": ["email", "age"],
"properties": {
"email": {"type": "string", "format": "email"},
"age": {"type": "integer", "minimum": 18}
}
}`
compiler := jsonschema.NewCompiler()
compiler.AddResource("schema.json", strings.NewReader(schemaJSON))
schema, err := compiler.Compile("schema.json")
if err != nil {
panic(err)
}
data := map[string]any{"email": "user@example.com", "age": 25}
if err := schema.Validate(data); err != nil {
fmt.Println("Invalid:", err)
} else {
fmt.Println("Valid")
}
}
실용적인 사용 사례
API 요청 검증
비즈니스 로직에 도달하기 전에 게이트웨이나 미들웨어 레이어에서 API 페이로드를 검증합니다.
설정 파일 검증
시작 시 애플리케이션 설정을 검증하고, 알 수 없는 런타임 오류 대신 명확한 오류 메시지로 빠르게 실패하도록 합니다.
JSON Schema vs 런타임 검증 라이브러리
| 접근 방식 | 이식성 | 언어 지원 | 학습 곡선 | 도구 |
|---|---|---|---|---|
| JSON Schema | 높음(언어 중립) | 주요 언어 전부 | 중간 | 우수 |
| TypeScript(Zod/Yup) | TypeScript만 | TypeScript/JS | 낮음 | 양호 |
| Pydantic(Python) | Python만 | Python | 낮음 | 양호 |
| Protobuf/gRPC | 높음(바이너리) | 전부 | 높음 | 우수 |
| OpenAPI spec | 높음 | 전부 | 중간 | 우수 |
JSON Schema는 폴리글랏 스택 전체에서 공유되는 단일 정규 스키마가 필요할 때 가장 유리합니다. 한 번 정의하면 어떤 언어에서도 검증할 수 있습니다.
흔한 실수
additionalProperties: false를 설정하지 않음 — 스키마가 여분의 필드를 받아들이게 되어 클라이언트가 예상치 못한 데이터를 쉽게 전달할 수 있습니다.
검증기 설정 없이 format 사용 — format: "email"은 어노테이션이지 제약이 아닙니다. 검증기에서 형식 검증을 명시적으로 활성화하지 않는 한 강제되지 않습니다.
드래프트 버전 혼용 — $schema에서 draft-07을 선언하면서 $defs(2019-09 이상)를 사용하면 정의되지 않은 동작이 발생합니다.
required 누락 — required가 없으면 모든 properties가 기본적으로 선택적입니다. properties는 있지만 required 배열이 없는 스키마는 {}에 대해 검증이 통과됩니다.
DB의 ID에 type: "integer" 사용 — 큰 정수 ID(64비트)는 JavaScript의 안전한 정수 범위를 초과할 수 있습니다. "type": "string" 또는 "maximum": 9007199254740991을 추가하는 것을 고려하세요.
온라인 JSON Schema 검증기
스키마를 샘플 데이터에 대해 로컬로 테스트하려면 검증기 설정·파일 로드·코드 실행이 필요합니다. ZeroTool JSON Schema 검증기는 그 모든 번거로움을 없애줍니다:
- JSON Schema와 샘플 JSON을 나란히 붙여 넣기
- 오류 경로 하이라이트와 즉각적인 검증
- draft-04·draft-06·draft-07·2019-09·2020-12 지원
- 100% 로컬 처리 — 데이터가 브라우저 밖으로 나가지 않음