파이썬 JSON 스키마 검증 가이드 jsonschema로 Draft 7 2019-09 2020-12 지원과 $ref format 커스텀 포맷 에러 메시지까지
🧩 실무 데이터 검증을 위한 파이썬 jsonschema 전체 흐름과 핵심 설정을 한 번에 정리합니다
데이터가 여러 팀과 서비스 사이를 오갈수록 JSON 구조가 미묘하게 달라져 장애가 생기는 일이 잦습니다.
작게는 필드 하나가 빠지거나 타입이 달라지는 사소한 실수부터, 버전이 다른 스키마가 섞여서 요청 자체가 실패하는 경우까지 다양합니다.
이럴 때 가장 확실한 안전장치는 명시적인 스키마와 자동화된 검증입니다.
파이썬 생태계에서는 jsonschema가 표준 규격을 따르는 대표 도구로 자리 잡았고, 팀 내 규칙을 스키마로 문서화해 배포 파이프라인과 테스트에 연결하기 좋습니다.
아래 글에서는 실제로 적용할 때 필요한 제목과 목차를 차근차근 안내하며, 불필요한 이론 설명 대신 프로젝트에 바로 옮겨 적을 수 있는 기준을 제시합니다.
이 글은 파이썬 JSON 검증에서 꼭 알아야 할 한 축인 스키마 규격과 검증기 설정을 중심으로 구성되어 있습니다.
핵심은 세 가지입니다.
첫째, Draft 7과 2019-09, 2020-12 같은 주요 규격의 차이를 이해해 프로젝트에 맞는 기준을 고르는 것.
둘째, $ref로 스키마를 재사용·모듈화하고 format 및 커스텀 포맷으로 도메인 규칙을 정확히 표현하는 것.
셋째, 검증 실패를 사용자와 로그가 이해할 수 있는 에러 메시지로 구성해 디버깅 시간을 줄이는 것입니다.
실무에서 흔히 마주치는 함정과 결정 포인트를 체계적으로 정리해, 테스트 코드와 배포 단계에서 신뢰할 수 있는 데이터 파이프라인을 만드는 데 도움이 되도록 구성했습니다.
📋 목차
🔗 파이썬 jsonschema로 JSON 검증 개요
jsonschema는 JSON Schema 표준을 구현한 파이썬 라이브러리로, 입력 JSON이 스키마에 맞는지 자동으로 검사해 줍니다.
핵심 장점은 명확한 실패 지점과 일관된 규칙 적용입니다.
Draft 7, 2019-09, 2020-12 규격을 폭넓게 지원하며, 팀과 서비스 간 데이터 계약을 코드로 명문화할 수 있습니다.
간단한 유효성 검사는 validate() 한 줄이면 충분하고, 더 세밀한 제어가 필요하면 Draft7Validator, Draft201909Validator, Draft202012Validator 같은 클래스 기반 검증기를 선택해 사용합니다.
또한 format 키워드와 FormatChecker를 통해 이메일, URI, 날짜·시간 등 도메인별 형식을 검증할 수 있습니다.
검증 흐름은 세 단계로 정리할 수 있습니다.
먼저 스키마를 정의하고, 이어서 검증할 JSON 인스턴스를 준비합니다.
그 다음 적절한 드래프트 버전에 맞는 검증기를 선택해 실행합니다.
초기 도입은 validate()로 시작하되, 대규모 프로젝트에서는 반복 검증과 상세 오류 수집을 위해 iter_errors()를 활용하는 구성이 권장됩니다.
실패 시에는 예외가 발생하며, 에러 객체에는 문제가 발생한 경로, 기대한 규칙, 실제 값 등의 정보가 담겨 디버깅 시간을 줄여 줍니다.
from jsonschema import validate, Draft202012Validator, FormatChecker
from jsonschema.exceptions import ValidationError
# 1) 스키마 정의 (Draft 2020-12)
schema = {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"email": {"type": "string", "format": "email"},
"price": {"type": "number", "minimum": 0},
},
"required": ["email", "price"],
"additionalProperties": False,
}
# 2) 간단 검증: 예외가 없으면 통과
validate({"email": "alice@example.com", "price": 9.99}, schema)
# 3) 정교한 검증: 드래프트 별 검증기 + 포맷 체크 + 에러 수집
validator = Draft202012Validator(schema, format_checker=FormatChecker())
errors = sorted(validator.iter_errors({"email": "not-an-email", "price": -5}), key=lambda e: e.path)
for err in errors:
# 친절한 메시지 설계 시 이 정보를 활용
print("path:", list(err.path), "| message:", err.message)
대규모 스키마에서는 $ref를 활용해 공통 정의를 재사용합니다.
최신 버전에서는 전통적인 RefResolver 대신 referencing.Registry 기반의 해석기가 권장되며, 로컬 파일과 원격 리소스를 안전하게 참조하도록 구성할 수 있습니다.
이는 여러 파일로 분리된 스키마를 결합할 때 일관된 참조 규칙을 제공해 유지보수성을 높입니다.
형식 검증이 필요한 경우 FormatChecker()를 주입해 date, date-time, uri, email 등의 기본 포맷을 활성화하고, 프로젝트 특화 규칙은 커스텀 포맷으로 확장합니다.
- 🛠️프로젝트의 표준 드래프트 선택: Draft 7 또는 2019-09, 2020-12 중 한 가지로 고정
- ⚙️간단 검증은 validate(), 상세 오류 수집은 iter_errors() 사용
- 🔗$ref 사용 시 최신 referencing.Registry 구성 고려
- 🔍이메일·URI·날짜·시간 등은 FormatChecker로 형식 검증 활성화
💡 TIP: CI 파이프라인에 스키마 검증을 넣으면 코드 머지 전에 잘못된 JSON 계약이 차단됩니다.
테스트에서는 iter_errors()를 사용해 모든 실패 사유를 한 번에 수집하고, 운영 로깅에는 친절한 메시지로 변환해 저장하는 방식을 추천합니다.
⚠️ 주의: 스키마의 드래프트 버전과 검증기 클래스가 혼용되면 예상치 못한 결과가 나올 수 있습니다.
스키마 상단의 $schema 선언과 실제로 사용하는 검증기의 드래프트를 반드시 일치시켜야 합니다.
🛠️ Draft 7 2019-09 2020-12 스키마 차이와 선택 기준
JSON Schema는 시간이 지날수록 점진적으로 발전해 왔습니다.
각 Draft 버전은 새로운 기능과 구조 개선을 포함하며, 검증 라이브러리도 이에 맞게 동작이 다릅니다.
파이썬의 jsonschema 라이브러리는 Draft 7부터 최신 2020-12까지 모두 지원하고 있어, 프로젝트 상황에 따라 최적의 버전을 선택할 수 있습니다.
이 섹션에서는 세 버전의 핵심 차이와 실제 적용 시 고려해야 할 기준을 정리했습니다.
📘 Draft 7 – 안정성과 호환성 중심
Draft 7은 현재까지도 많은 프로젝트에서 사용되는 안정적인 버전입니다.
기존 시스템과의 호환성이 높고, 대부분의 툴링 및 IDE 지원이 완성되어 있습니다.
특히 if/then/else 조건문, const 키워드가 도입되어 검증 규칙 표현력이 크게 향상되었습니다.
단, 2019-09 이후에 추가된 $defs나 unevaluatedProperties 같은 최신 문법은 사용할 수 없습니다.
📙 Draft 2019-09 – $id 체계 개선과 $defs 도입
2019-09 버전은 스키마 참조 체계를 전면 개편했습니다.
기존 definitions 대신 $defs를 사용하며, URI 기반 $id 관리 방식이 세분화되어 다중 파일 간 참조가 보다 직관적으로 작동합니다.
또한 contentMediaType과 contentEncoding 키워드가 추가되어 Base64 등 특정 인코딩 형식의 데이터를 검증할 수 있게 되었습니다.
이 버전은 모듈형 스키마 설계가 필요한 프로젝트에 특히 유리합니다.
📗 Draft 2020-12 – 논리 연산과 동적 참조의 완성형
2020-12는 JSON Schema 진화의 정점으로 평가받습니다.
$dynamicRef와 $dynamicAnchor를 도입하여 계층적 스키마 내 동적 참조가 가능해졌습니다.
이는 복잡한 구성요소를 가진 API 규격에서 매우 강력하게 작동합니다.
또한 unevaluatedProperties 및 unevaluatedItems 속성으로 이미 검증된 필드 외의 요소를 자동 필터링할 수 있어, 유연함과 제어력을 동시에 제공합니다.
| Draft 버전 | 주요 특징 |
|---|---|
| Draft 7 | 조건문(if/then/else), const 지원, 호환성 우수 |
| 2019-09 | $defs 도입, $id 체계 개선, 모듈형 참조 강화 |
| 2020-12 | 동적 참조($dynamicRef), unevaluatedProperties 추가 |
실무에서는 기존 시스템과의 호환이 중요하다면 Draft 7을, 새로운 API 또는 복잡한 스키마 관리가 필요하다면 Draft 2020-12를 사용하는 것이 좋습니다.
2019-09는 그 사이에서 단계적 전환용으로 적합합니다.
한 프로젝트 내에서는 반드시 하나의 Draft 규격으로 통일해야 하며, CI 테스트 시 스키마 버전 불일치를 점검하도록 구성하는 것이 바람직합니다.
💎 핵심 포인트:
Draft 버전이 높을수록 스키마 작성은 유연해지지만, 지원하지 않는 구버전 검증기에서는 오류가 발생할 수 있습니다. 반드시 사용하는 파이썬 jsonschema 버전이 선택한 Draft를 지원하는지 확인하세요.
⚙️ $ref로 스키마 재사용과 모듈화
스키마가 커질수록 중복되는 정의가 많아지고 유지보수가 어려워집니다.
이때 $ref를 활용하면 공통 규칙을 분리하고 여러 스키마에서 재사용할 수 있습니다.
파이썬 jsonschema는 $ref 해석을 자동으로 처리하며, 로컬 파일·URL·메모리 객체까지 폭넓게 지원합니다.
이는 API, 마이크로서비스, 데이터 파이프라인에서 데이터 계약을 일관되게 유지하는 핵심 요소입니다.
📂 $ref 기본 구조와 내부 참조
스키마 내부에서 $ref는 다른 정의된 객체를 참조할 때 사용합니다.
하나의 JSON 파일 내에서도 $defs 영역을 만들어 공통 정의를 모아두고, 필요한 곳에서 “$ref”: “#/$defs/이름” 형태로 불러옵니다.
이 방식은 반복적인 필드 정의를 줄이고 검증 규칙 변경 시 단일 지점에서 수정할 수 있게 해줍니다.
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://example.com/user.schema.json",
"type": "object",
"$defs": {
"email": {
"type": "string",
"format": "email"
},
"price": {
"type": "number",
"minimum": 0
}
},
"properties": {
"userEmail": { "$ref": "#/$defs/email" },
"productPrice": { "$ref": "#/$defs/price" }
},
"required": ["userEmail", "productPrice"]
}
이처럼 내부 참조를 사용하면 스키마 관리가 단순해집니다.
특히 복잡한 서비스에서는 공통 스키마를 별도의 파일로 관리하여 다양한 검증기에 동일한 정의를 전달할 수 있습니다.
이때 $id를 명시적으로 지정하면 다른 파일에서 이 스키마를 $ref로 불러올 때 식별자로 사용할 수 있습니다.
🌐 외부 스키마 참조와 Registry 사용
jsonschema 4.x 이후부터는 기존의 RefResolver가 더 이상 권장되지 않습니다.
대신 referencing 모듈의 Registry를 통해 안전하고 명시적인 참조를 수행합니다.
이를 통해 네트워크 요청 없이 로컬 캐시나 메모리 내 사전 정의를 기반으로 스키마를 연결할 수 있습니다.
보안상 외부 요청을 제한해야 하는 환경에서도 유용합니다.
from jsonschema import Draft202012Validator
from referencing import Registry, Resource
base_schema = {
"$id": "https://example.com/base.schema.json",
"type": "object",
"properties": {
"id": {"type": "integer"}
}
}
main_schema = {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"user": {"$ref": "https://example.com/base.schema.json"}
}
}
registry = Registry().with_resource(Resource.from_contents(base_schema))
validator = Draft202012Validator(main_schema, registry=registry)
validator.validate({"user": {"id": 1}})
이 방식은 네트워크 요청 없이 스키마를 로드하므로 성능과 보안 모두에서 효율적입니다.
복수의 참조 스키마가 있는 대규모 시스템에서는 Registry를 활용해 버전별 스키마를 일관되게 관리할 수 있습니다.
또한 $id와 $ref URI 구조를 규칙적으로 설계해두면, IDE 자동 완성과 문서 생성 도구에서도 쉽게 연결할 수 있습니다.
💎 핵심 포인트:
$ref는 스키마 재사용의 핵심이지만, 순환 참조가 발생하면 검증이 무한 루프에 빠질 수 있습니다. 외부 스키마 구조 설계 시 반드시 참조 깊이를 제한하고, 검증기 버전이 최신인지 확인해야 합니다.
🔍 format 기본 포맷과 커스텀 포맷 검증
JSON Schema의 format 키워드는 문자열 데이터의 추가적인 제약을 정의할 때 사용됩니다.
예를 들어 “email”, “uri”, “date-time” 등은 JSON 값의 형식이 표준 패턴을 따르는지 검사합니다.
파이썬의 jsonschema에서는 이 기능을 FormatChecker로 구현하며, 검증기 객체에 주입하여 활성화합니다.
✅ 기본 제공 포맷
기본적으로 지원되는 포맷은 다음과 같습니다.
이들은 대부분 RFC 3339, RFC 5322 등 국제 표준 규격을 기반으로 합니다.
| 포맷 | 설명 |
|---|---|
| RFC 5322 형식의 이메일 주소 | |
| uri | 표준 URI 스키마 |
| ipv4 / ipv6 | IPv4, IPv6 주소 형식 |
| date / date-time | ISO8601 규격 날짜 및 시간 |
| hostname | 도메인 이름 형식 |
기본 포맷은 자동으로 검증되지 않으며, 반드시 format_checker=FormatChecker()를 지정해야 활성화됩니다.
이 설정이 없으면 포맷 키워드는 단순 주석처럼 무시됩니다.
from jsonschema import Draft202012Validator, FormatChecker
schema = {
"type": "object",
"properties": {
"email": {"type": "string", "format": "email"},
"homepage": {"type": "string", "format": "uri"},
},
"required": ["email"]
}
data = {"email": "invalid-email", "homepage": "https://example.com"}
validator = Draft202012Validator(schema, format_checker=FormatChecker())
for err in validator.iter_errors(data):
print(err.message)
# 출력: 'invalid-email' is not a 'email'
🧩 커스텀 포맷 추가하기
기본 포맷 외에도 도메인 규칙에 맞춘 커스텀 검증기를 추가할 수 있습니다.
예를 들어 한국의 주민등록번호나 특정 코드 규칙 등을 정의할 때 유용합니다.
FormatChecker 객체의 checks() 데코레이터를 활용하면 간단하게 등록할 수 있습니다.
from jsonschema import FormatChecker, Draft202012Validator
import re
checker = FormatChecker()
@checker.checks("kr-rrn")
def is_korean_rrn(value):
return bool(re.match(r"^\d{6}-\d{7}$", value))
schema = {
"type": "object",
"properties": {
"rrn": {"type": "string", "format": "kr-rrn"}
}
}
validator = Draft202012Validator(schema, format_checker=checker)
validator.validate({"rrn": "900101-1234567"}) # ✅ 통과
validator.validate({"rrn": "invalid"}) # ❌ 예외 발생
커스텀 포맷은 일반 포맷과 동일한 방식으로 작동하며, 프로젝트 전역의 포맷 정책을 통일할 수 있습니다.
특히 여러 서비스가 공통 포맷을 공유할 경우, 중앙 FormatChecker 모듈을 만들어 관리하면 유지보수가 훨씬 쉬워집니다.
💎 핵심 포인트:
format 검증은 단순 문자열 패턴이 아닌, 실질적인 데이터 형식 유효성을 보장하는 장치입니다. 커스텀 포맷을 정의할 때는 실제 도메인 로직과 동일한 규칙을 적용해야 합니다.
💡 검증 결과 처리와 친절한 에러 메시지 설계
스키마 검증의 마지막 단계는 오류를 사용자나 로그가 이해할 수 있는 형태로 전달하는 것입니다.
단순히 “ValidationError”를 출력하는 대신, 어떤 필드가 어떤 이유로 실패했는지를 구체적으로 표현해야 합니다.
파이썬 jsonschema는 풍부한 오류 객체를 제공하므로, 이를 적절히 가공하면 개발자와 사용자 모두에게 도움이 되는 메시지를 만들 수 있습니다.
🧠 ValidationError 객체 활용
검증기(Validator)의 iter_errors() 메서드는 각 오류에 대한 세부 정보를 담은 ValidationError 객체를 반환합니다.
여기에는 실패한 경로(path), 메시지(message), 스키마 위치(schema_path) 등이 포함됩니다.
이를 이용하면 API 응답이나 로그에 의미 있는 구조화 데이터를 남길 수 있습니다.
from jsonschema import Draft202012Validator
schema = {
"type": "object",
"properties": {
"age": {"type": "integer", "minimum": 0},
"email": {"type": "string", "format": "email"}
},
"required": ["age", "email"]
}
data = {"age": -2, "email": "not-email"}
validator = Draft202012Validator(schema)
errors = sorted(validator.iter_errors(data), key=lambda e: e.path)
for e in errors:
print(f"경로: {'.'.join(map(str, e.path)) or 'root'}")
print(f"메시지: {e.message}")
print(f"규칙: {e.validator}")
print("---")
출력 예시는 다음과 같습니다.
💬 경로: age
메시지: -2 is less than the minimum of 0
규칙: minimum
—
경로: email
메시지: ‘not-email’ is not a ’email’
규칙: format
이 정보를 바탕으로 REST API나 CLI 툴에서는 다음과 같이 사용자 친화적인 메시지를 구성할 수 있습니다.
예를 들어 “나이는 0 이상이어야 합니다.”, “이메일 주소 형식이 올바르지 않습니다.”처럼 구체적인 설명을 제공하면 디버깅 효율이 높아집니다.
📦 다국어·로깅 환경에 맞는 메시지 구조화
대규모 프로젝트에서는 검증 오류를 단순 문자열로 남기기보다, 코드·필드·메시지를 구조화해 저장하는 것이 좋습니다.
예를 들어 에러 로그를 다음과 같은 JSON 형태로 관리하면, 이후 분석이나 번역 처리도 수월해집니다.
[
{
"field": "age",
"rule": "minimum",
"message": "나이는 0 이상이어야 합니다."
},
{
"field": "email",
"rule": "format",
"message": "이메일 형식이 잘못되었습니다."
}
]
API 서버나 로그 수집 시스템에서는 이러한 구조화된 메시지를 통해 모니터링 대시보드를 구성하거나, UI에서 에러 필드를 하이라이트할 수 있습니다.
또한 jsonschema.exceptions.ValidationError를 상속받아 커스텀 예외 클래스를 정의하면, 프로젝트 전반의 에러 처리 규약을 통일할 수 있습니다.
💎 핵심 포인트:
검증 결과는 단순 실패가 아니라 데이터 품질 개선의 출발점입니다. 사용자가 이해할 수 있는 메시지를 제공하고, 내부적으로는 구조화된 에러 정보를 활용하면 유지보수와 모니터링 품질이 크게 향상됩니다.
❓ 자주 묻는 질문 FAQ
jsonschema는 어떤 드래프트 버전을 기본으로 사용하나요?
다만 하위 호환성을 위해 Draft 7, 2019-09도 선택적으로 사용할 수 있습니다.
스키마 상단의 $schema 선언으로 명시해주는 것이 가장 안전한 방법입니다.
RefResolver가 사라졌는데, 기존 코드는 어떻게 바꿔야 하나요?
기존처럼 URL 기반으로 외부 스키마를 불러올 수 있으며, 로컬 캐시나 리소스 객체로 미리 등록하는 방식으로 교체하면 됩니다.
format 검증이 동작하지 않을 때 원인은 무엇인가요?
검증기를 생성할 때 format_checker=FormatChecker()를 전달해야 포맷 검증이 활성화됩니다.
$ref를 여러 파일에 걸쳐 사용할 때 주의할 점은 무엇인가요?
순환 참조가 발생하지 않도록 Registry를 이용해 참조 깊이를 제어하는 것이 좋습니다.
Draft 7에서 2020-12로 마이그레이션하려면 무엇을 바꿔야 하나요?
또한 unevaluatedProperties와 $dynamicRef 같은 새 키워드를 검토하면 최신 기능을 최대한 활용할 수 있습니다.
검증 속도를 높이기 위한 팁이 있나요?
또한 iter_errors() 대신 is_valid()를 사용하면 빠른 참·거짓 판별이 가능합니다.
커스텀 포맷은 어디에 저장해 관리하는 게 좋을까요?
여러 서비스에서 같은 형식을 공유할 때 중복 정의를 방지할 수 있습니다.
에러 메시지를 다국어로 출력하려면 어떻게 하나요?
예를 들어 Django 프로젝트에서는 gettext를 통해 자연스럽게 다국어 대응이 가능합니다.
📘 jsonschema로 완성하는 데이터 신뢰성과 자동 검증의 모든 것
파이썬의 jsonschema는 단순한 검증 도구를 넘어, 데이터 품질을 보장하는 강력한 규약 시스템입니다.
Draft 7, 2019-09, 2020-12까지 모든 주요 스키마 버전을 지원하며, $ref로 재사용성과 유지보수를 향상시키고, format 및 커스텀 포맷으로 실질적인 비즈니스 규칙을 구현할 수 있습니다.
또한 친절한 에러 메시지 설계로 개발자와 사용자가 모두 이해할 수 있는 검증 환경을 제공합니다.
결국 핵심은 “명세화와 자동화”입니다.
모든 서비스의 데이터 규칙을 문서로 남기고, 코드로 강제함으로써 오류를 미리 차단하고 일관된 품질을 유지할 수 있습니다.
팀 간 협업과 API 안정성 확보를 목표로 한다면, jsonschema를 파이썬 프로젝트의 기본 검증 계층으로 도입하는 것이 가장 효율적인 선택입니다.
🏷️ 관련 태그 : jsonschema, 파이썬데이터검증, JSON스키마, Draft202012, 데이터표준화, 커스텀포맷, $ref, FormatChecker, 데이터품질, ValidationError