JSON Schema 입문: 데이터 구조를 정의하고 검증하기
API를 개발하다 보면 "이 필드가 항상 존재하는가?", "이 값은 어떤 타입인가?"를 코드로 직접 검사하는 코드를 반복해서 작성하게 됩니다. JSON Schema는 이런 검증 로직을 선언적으로 표현하는 표준 방법입니다. 한 번 스키마를 작성하면 검증, 문서화, 폼 자동 생성까지 재활용할 수 있습니다.
JSON Schema란 무엇인가
JSON Schema는 JSON 데이터의 구조를 기술하는 JSON 문서입니다. "이 객체는 name(문자열)과 age(양의 정수) 필드를 가져야 한다"는 규칙을 JSON으로 표현합니다.
현재 가장 널리 쓰이는 버전은 Draft 2020-12이며, $schema 키워드로 버전을 명시합니다.
{"$schema": "https://json-schema.org/draft/2020-12/schema","$id": "https://example.com/user.schema.json","title": "User","description": "사용자 정보","type": "object","properties": {"name": { "type": "string" },"age": { "type": "integer", "minimum": 0 }},"required": ["name"]}
기본 타입 정의
JSON Schema는 JSON의 6가지 타입을 모두 지원합니다.
string
{"type": "string","minLength": 1,"maxLength": 100,"pattern": "^[a-zA-Z가-힣 ]+$"}
number / integer
{"type": "number","minimum": 0,"maximum": 100,"multipleOf": 0.5}
number는 부동소수점을 포함하고, integer는 정수만 허용합니다.
boolean
{ "type": "boolean" }
null
{ "type": "null" }
여러 타입을 허용하려면 배열로 표현합니다.
{ "type": ["string", "null"] }
array
{"type": "array","items": { "type": "string" },"minItems": 1,"maxItems": 10,"uniqueItems": true}
items로 배열 원소의 타입을 지정합니다. uniqueItems: true는 중복을 금지합니다.
object
{"type": "object","properties": {"id": { "type": "integer" },"email": { "type": "string", "format": "email" }},"additionalProperties": false}
additionalProperties: false를 설정하면 properties에 명시되지 않은 키를 거부합니다.
필수 필드와 선택 필드
required 배열에 반드시 존재해야 하는 필드명을 나열합니다.
{"type": "object","properties": {"username": { "type": "string" },"email": { "type": "string", "format": "email" },"bio": { "type": "string" }},"required": ["username", "email"]}
위 스키마에서 username과 email은 필수, bio는 선택입니다. required에 없는 필드는 존재하지 않아도 검증을 통과합니다.
고급 기능
enum: 허용 값 열거
특정 값만 허용하고 싶을 때 사용합니다.
{"type": "string","enum": ["pending", "active", "inactive", "deleted"]}
const: 고정 값
{"properties": {"version": { "const": "2.0" }}}
pattern: 정규식 검증
{"type": "string","pattern": "^\\d{3}-\\d{4}-\\d{4}$"}
format: 의미론적 포맷 검증
| format 값 | 설명 |
|---|---|
email | 이메일 주소 |
uri | URI |
date | 날짜 (YYYY-MM-DD) |
date-time | ISO 8601 날짜+시간 |
uuid | UUID v4 |
ipv4 | IPv4 주소 |
$ref: 스키마 재사용
반복되는 스키마를 $defs에 정의하고 $ref로 참조합니다.
{"$defs": {"Address": {"type": "object","properties": {"street": { "type": "string" },"city": { "type": "string" }},"required": ["street", "city"]}},"type": "object","properties": {"homeAddress": { "$ref": "#/$defs/Address" },"workAddress": { "$ref": "#/$defs/Address" }}}
조합 키워드: allOf, anyOf, oneOf
{"oneOf": [{ "type": "string", "maxLength": 5 },{ "type": "number", "minimum": 0 }]}
allOf: 모든 서브스키마를 만족해야 함anyOf: 하나 이상의 서브스키마를 만족해야 함oneOf: 정확히 하나의 서브스키마만 만족해야 함
실전 활용
API 문서화
OpenAPI(Swagger) 스펙은 내부적으로 JSON Schema를 사용합니다. 스키마를 한 번 작성하면 API 문서가 자동으로 생성됩니다.
components:schemas:CreateUserRequest:type: objectrequired: [username, email]properties:username:type: stringminLength: 3email:type: stringformat: email
런타임 검증 (Node.js)
import Ajv from 'ajv';import addFormats from 'ajv-formats';const ajv = new Ajv();addFormats(ajv);const schema = {type: 'object',properties: {email: { type: 'string', format: 'email' },age: { type: 'integer', minimum: 0 },},required: ['email'],};const validate = ajv.compile(schema);const valid = validate({ email: 'user@example.com', age: 25 });if (!valid) {console.error(validate.errors);}
폼 자동 생성
React JSON Schema Form(@rjsf/core) 같은 라이브러리는 JSON Schema로부터 HTML 폼을 자동으로 렌더링합니다. 스키마 변경만으로 폼 구조가 업데이트됩니다.
데이터 파이프라인 검증
ETL 파이프라인에서 입력 데이터를 스키마로 검증하면, 잘못된 데이터가 다음 단계로 넘어가는 것을 방지할 수 있습니다.
import jsonschemaschema = {"type": "object","properties": {"event": {"type": "string"},"timestamp": {"type": "string", "format": "date-time"}},"required": ["event", "timestamp"]}jsonschema.validate(instance=data, schema=schema)
JSONKit Schema 도구 활용
JSONKit의 Schema 도구를 사용하면 JSON 데이터를 붙여넣어 스키마를 자동 추론하거나, 직접 작성한 스키마로 데이터를 검증할 수 있습니다. 오류가 발생하면 어느 경로의 어느 규칙을 위반했는지 상세히 표시해 줍니다. 브라우저에서 바로 실행되므로 민감한 데이터를 외부로 전송할 걱정 없이 사용할 수 있습니다.
마무리
JSON Schema는 처음에는 다소 장황하게 느껴질 수 있지만, 한 번 익혀두면 API 개발, 테스트, 문서화, 폼 생성 등 다양한 영역에서 반복 코드를 줄여줍니다. 작은 스키마부터 작성해보고, $ref로 점진적으로 모듈화해 나가는 것을 권장합니다.