JSON Schema 유효성 검사란?
JSON Schema 유효성 검사는 JSON 문서가 JSON Schema에 정의된 구조적·값 제약 조건을 준수하는지 확인하는 과정입니다. Schema 자체도 JSON 문서로, 데이터의 예상 형태를 기술합니다. 어떤 프로퍼티가 필수인지, 각 타입이 무엇이어야 하는지, 숫자의 허용 범위, 문자열 패턴, 배열 길이 등을 정의합니다. JSON Schema 명세는 json-schema.org에서 관리되며 일련의 IETF 초안으로 게시됩니다. Draft 7과 Draft 2020-12가 가장 널리 채택되어 있습니다.
단순 JSON 유효성 검사는 구문만 확인합니다(괄호가 올바르게 닫혔는지, 문자열에 따옴표가 있는지 등). Schema 유효성 검사는 한 걸음 더 나아가 구조적 계약을 검사합니다. 이 API 응답에 항상 정수형인 "id" 필드가 포함되어 있는지, "status" 필드가 허용된 세 가지 값 중 하나인지, 중첩 객체의 형태가 올바른지 등을 확인합니다. 이러한 구조적 검증은 구문 검사가 잡아내지 못하는 버그를 발견합니다. 구문상 유효한 JSON이라도 애플리케이션에 의미상으로는 잘못될 수 있기 때문입니다.
JSON Schema는 OpenAPI/Swagger 정의, 설정 파일 유효성 검사, 폼 유효성 검사, 데이터베이스 문서 제약 조건, 자동화 테스트 등에 활용됩니다. Ajv(JavaScript), jsonschema(Python), check-jsonschema(CLI) 같은 도구들이 명세를 구현하여 프로그래밍 방식으로 데이터를 검사할 수 있게 해줍니다. 이 온라인 검사기는 Schema와 데이터 문서를 모두 붙여넣어 라이브러리 설치 없이 즉시 준수 여부를 확인할 수 있습니다.
온라인 JSON Schema 검사기를 사용하는 이유
Schema를 작성하고 유효성 오류를 직접 디버깅하는 것은 시간이 많이 걸립니다. 온라인 JSON Schema 검사기는 데이터가 Schema와 일치하는지 즉각적인 피드백을 제공하며, 실패한 프로퍼티를 명확한 오류 메시지로 정확히 가리킵니다.
JSON Schema 유효성 검사 활용 사례
JSON Schema 키워드 참조
JSON Schema는 검사 대상 데이터에 각각 제약을 부과하는 키워드로 구성됩니다. 아래 표는 Draft 7 이상에서 가장 많이 사용되는 키워드를 나열합니다. 모든 키워드는 같은 Schema 객체 안에서 다른 키워드와 조합할 수 있습니다.
| 키워드 | 용도 | 예시 |
|---|---|---|
| type | Restricts the data type | "type": "string" |
| properties | Defines expected object keys and their schemas | "properties": { "name": { "type": "string" } } |
| required | Lists mandatory properties | "required": ["id", "name"] |
| items | Schema for array elements | "items": { "type": "number" } |
| enum | Restricts value to a fixed set | "enum": ["active", "inactive"] |
| pattern | Regex constraint on strings | "pattern": "^[A-Z]{2}\\d{4}$" |
| minimum / maximum | Numeric range bounds | "minimum": 0, "maximum": 100 |
| minLength / maxLength | String length bounds | "minLength": 1, "maxLength": 255 |
| $ref | Reuses another schema by URI | "$ref": "#/$defs/address" |
| additionalProperties | Controls extra keys in objects | "additionalProperties": false |
| anyOf / oneOf / allOf | Combines multiple schemas logically | "anyOf": [{ "type": "string" }, { "type": "null" }] |
| if / then / else | Conditional schema application | "if": { "properties": { "type": { "const": "email" } } } |
JSON Schema Draft 비교: Draft 7 vs 2019-09 vs 2020-12
JSON Schema는 여러 Draft 버전을 거쳤습니다. 2018년에 게시된 Draft 7이 도구 지원 면에서 가장 널리 지원됩니다. Draft 2019-09는 $defs(definitions 대체), unevaluatedProperties, $recursiveRef를 도입했습니다. 최신 안정 릴리스인 Draft 2020-12는 $recursiveRef를 $dynamicRef로 교체하고 튜플 유효성 검사를 위한 prefixItems를 도입했습니다. Draft를 선택할 때는 유효성 검사 라이브러리가 해당 Draft를 지원하는지 확인하세요. Ajv는 세 Draft 모두 지원합니다. Python의 jsonschema 라이브러리는 버전 4.0부터 2020-12까지 지원합니다.
| 기능 | Draft 7 | Draft 2019-09 | Draft 2020-12 |
|---|---|---|---|
| $schema URI | draft-07/schema# | 2019-09/schema | 2020-12/schema |
| if / then / else | Yes | Yes | Yes |
| $defs (definitions) | definitions | $defs | $defs |
| $ref alongside keys | No (sibling ignored) | Yes | Yes |
| $dynamicRef | No | No ($recursiveRef) | Yes |
| prefixItems | No (use items array) | No (use items array) | Yes |
| unevaluatedProperties | No | Yes | Yes |
| $vocabulary | No | Yes | Yes |
코드 예시
아래 예시는 프로그래밍 방식으로 JSON을 Schema에 대해 검사하는 방법을 보여줍니다. 각 언어 생태계에서 잘 유지 관리되는 라이브러리를 사용합니다.
import Ajv from 'ajv';
const ajv = new Ajv();
const schema = {
type: 'object',
properties: {
name: { type: 'string', minLength: 1 },
age: { type: 'integer', minimum: 0 },
email: { type: 'string', format: 'email' }
},
required: ['name', 'email'],
additionalProperties: false
};
const data = { name: 'Alice', age: 30, email: 'alice@example.com' };
const validate = ajv.compile(schema);
const valid = validate(data);
console.log(valid); // → true
console.log(validate.errors); // → null
// Invalid data — missing required "email"
validate({ name: 'Bob', age: 25 });
console.log(validate.errors);
// → [{ instancePath: '', keyword: 'required', params: { missingProperty: 'email' } }]from jsonschema import validate, ValidationError
schema = {
"type": "object",
"properties": {
"name": {"type": "string", "minLength": 1},
"age": {"type": "integer", "minimum": 0},
"tags": {
"type": "array",
"items": {"type": "string"},
"uniqueItems": True
}
},
"required": ["name"]
}
# Valid data
validate(instance={"name": "Alice", "age": 30, "tags": ["admin"]}, schema=schema)
# → No exception raised
# Invalid data — wrong type for "age"
try:
validate(instance={"name": "Alice", "age": "thirty"}, schema=schema)
except ValidationError as e:
print(e.message)
# → 'thirty' is not of type 'integer'
print(e.json_path)
# → $.agepackage main
import (
"fmt"
"strings"
"github.com/santhosh-tekuri/jsonschema/v5"
)
func main() {
schemaJSON := `{
"type": "object",
"properties": {
"id": { "type": "integer" },
"status": { "enum": ["active", "inactive"] }
},
"required": ["id", "status"]
}`
compiler := jsonschema.NewCompiler()
compiler.AddResource("schema.json", strings.NewReader(schemaJSON))
schema, _ := compiler.Compile("schema.json")
// Valid data
data := map[string]interface{}{"id": 1, "status": "active"}
err := schema.Validate(data)
fmt.Println(err) // → <nil>
// Invalid — missing "status"
bad := map[string]interface{}{"id": 2}
err = schema.Validate(bad)
fmt.Println(err) // → validation failed: missing properties: 'status'
}# Install via pip pip install check-jsonschema # Validate a file against a schema check-jsonschema --schemafile schema.json data.json # → ok -- validation done # Validate against a remote schema (e.g., GitHub Actions workflow) check-jsonschema --builtin-schema vendor.github-workflows my-workflow.yml # Validate multiple files at once check-jsonschema --schemafile schema.json file1.json file2.json file3.json