JSON 스키마 만들기: 타입 판정 규칙

JSON 데이터를 붙여넣으면 곧바로 Draft-07 형식의 JSON 스키마가 만들어지는 이유는, 도구가 값 하나하나를 재귀적으로 훑으며 타입을 자동으로 판정하기 때문입니다.

API 응답 예시나 설정 파일을 받아 검증 규칙을 급히 만들어야 하는 개발자, 그리고 결과에 나오는 required·anyOf 같은 필드가 정확히 무엇을 뜻하는지 궁금한 사람이 이 글의 대상입니다.

판정 규칙과 결과를 읽는 법만 정리하고, 스키마를 어떻게 설계해야 좋은지 같은 판단은 다루지 않습니다.

요약 ① 값의 타입은 null → 배열 → object/string/number/boolean 순서로 자동 판정되며, 따옴표로 감싼 숫자는 무조건 문자열로 처리됩니다. ② 배열 원소가 전부 같은 타입이면 첫 번째 원소 하나만 보고 items를 만들고, 타입이 섞여 있으면 anyOf로 타입별 예시를 나열합니다. ③ '모든 속성을 필수로 설정'을 체크하면 해당 객체의 모든 키가 그대로 required에 들어가며, 스키마 자체는 입력한 예시 하나에서 나온 추정치일 뿐입니다.

API 응답 하나 받아놓고 스키마부터 손으로 짜본 적 있다면

백엔드에서 넘어온 JSON 응답 예시 하나만 손에 쥐고 있는 상황을 생각해 보겠습니다. 이 예시를 바탕으로 프런트엔드 검증 코드나 API 문서에 넣을 JSON 스키마를 만들어야 합니다.

문제는 필드가 열 개, 스무 개로 늘어나는 순간부터입니다. 중첩된 객체와 배열, null이 섞인 값을 하나씩 손으로 옮겨 적다 보면 괄호나 쉼표를 빠뜨리기 쉽습니다.

특히 배열 안에 타입이 섞여 있을 때 anyOf를 쓰는 문법이나, 어떤 필드를 required에 넣을지 판단하는 기준은 매번 헷갈리는 지점입니다.

도구 없이 손으로 Draft-07 스키마 쓰는 법

Draft-07 JSON 스키마는 몇 가지 키워드 조합으로 이뤄져 있습니다. 값 하나를 스키마로 옮기는 규칙은 이렇습니다.

  • 문자열 → { "type": "string" }
  • 숫자(정수·소수 구분 없이) → { "type": "number" }
  • 참/거짓 → { "type": "boolean" }
  • null → { "type": "null" }
  • 객체 → { "type": "object", "properties": { ... } }
  • 배열 → { "type": "array", "items": { ... } }

예시 JSON에 규칙을 그대로 적용해 보면

이 규칙을 예시 JSON에 그대로 옮겨보겠습니다.

{
  "id": 1024,
  "zipCode": "06236",
  "name": "홍길동",
  "isActive": true,
  "note": null,
  "address": { "city": "서울", "district": "강남구" },
  "tags": ["vip", "return"],
  "history": [1, "pending", true]
}
  1. 최상위 값이 객체이므로 최상위 스키마는 "type": "object"로 시작하고, properties 안에 각 키를 하나씩 적습니다.
  2. id는 따옴표 없는 숫자이므로 number, zipCode는 따옴표로 감싸여 있으므로 string입니다. 값에 따옴표가 있는지 없는지가 유일한 판단 기준입니다.
  3. address처럼 값이 또 다른 객체이면 그 안에서도 똑같이 type: objectproperties를 반복해서 적습니다.
  4. tags처럼 배열 원소가 전부 같은 타입이면 그중 하나를 대표로 삼아 items에 그 타입 하나만 적습니다. history처럼 원소 타입이 섞여 있으면 items 안에 anyOf를 두고, 나온 타입마다 하나씩 스키마를 나열합니다.
  5. 이 데이터에서 실제로 항상 존재해야 하는 키를 사람이 직접 판단해 required 배열에 적습니다. 이 판단은 예시 하나가 아니라 실제 데이터 전체를 아는 사람만 정확히 할 수 있는 부분입니다.
  6. 맨 위에 "$schema": "http://json-schema.org/draft-07/schema#"를 적고, 필요하면 title을 추가해 마무리합니다.

이렇게 손으로 옮기면 결과는 아래와 같습니다.

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "properties": {
    "id": { "type": "number" },
    "zipCode": { "type": "string" },
    "name": { "type": "string" },
    "isActive": { "type": "boolean" },
    "note": { "type": "null" },
    "address": {
      "type": "object",
      "properties": {
        "city": { "type": "string" },
        "district": { "type": "string" }
      }
    },
    "tags": { "type": "array", "items": { "type": "string" } },
    "history": {
      "type": "array",
      "items": {
        "anyOf": [
          { "type": "number" },
          { "type": "string" },
          { "type": "boolean" }
        ]
      }
    }
  }
}

필드가 몇 개뿐이면 이 순서를 그대로 따라가는 것으로 충분합니다. 다만 필드가 많아지고 중첩이 깊어질수록 같은 판정 규칙을 손으로 반복하는 작업이 늘어납니다.

저희 도구로 확인하기.

JSON 스키마 생성기

JSON을 붙여넣으면 브라우저에서 즉시 Draft-07 스키마를 만들어 주며, 입력한 데이터는 서버로 전송되지 않습니다.

결과를 읽을 때 자주 헷갈리는 지점

생성된 스키마를 눈으로 확인할 때 자주 오해가 생기는 지점들을 정리했습니다.

흔한 오해실제 동작
"06236"처럼 숫자로만 된 값도 number로 잡힌다따옴표로 감싸져 있으면 무조건 string 타입입니다
정수는 integer, 소수는 number로 구분된다typeof 기준이라 정수·소수 구분 없이 항상 number입니다
required 체크는 필요한 필드만 골라 담아준다체크하면 그 객체의 모든 키가 예외 없이 required에 들어갑니다
배열 원소가 여러 개면 전부 살펴서 합쳐 만든다타입이 같으면 첫 번째 원소 하나만 보고 items를 만듭니다
생성된 스키마는 가능한 모든 데이터 형태를 담보한다입력한 예시 하나만 보고 추론한 결과일 뿐입니다

배열이 객체로 이뤄졌을 때, 그리고 몇 가지 예외

배열 원소가 전부 객체일 때는 이 규칙이 특히 눈에 띄게 나타납니다. 원소가 모두 "object" 타입으로 같다고 판단되면, 첫 번째 객체 하나의 키 구성만으로 items.properties가 만들어집니다.

두 번째 이후 객체에만 있는 키는 스키마에 전혀 나타나지 않습니다. 실제 데이터에는 있는 필드인데 생성된 스키마에는 빠져 있다면, 대개 이 규칙 때문입니다.

빈 배열을 넣으면 items는 아무 제약이 없는 {}로 채워집니다. 원소가 하나도 없어 타입을 판정할 근거 자체가 없기 때문입니다.

제목(title) 입력칸을 비워두면 생성된 스키마에 title 키 자체가 들어가지 않습니다. 값을 채워야만 $schema 바로 아래에 title이 추가됩니다.

정리

  • 값의 타입은 null → 배열 → object/string/number/boolean 순서로 자동 판정되며, 따옴표 유무가 문자열과 숫자를 가르는 유일한 기준입니다.
  • 정수와 소수는 구분 없이 항상 number로 표시됩니다.
  • 배열은 원소 타입이 전부 같으면 첫 번째 원소만 보고 items를 만들고, 타입이 섞이면 anyOf로 타입별 예시를 나열합니다.
  • required는 체크박스를 켰을 때만 생기며, 그 객체의 모든 키를 예외 없이 포함합니다.
  • 생성된 스키마는 입력한 예시 하나에서 추론한 결과이므로, 그 예시에 없던 필드나 타입 조합까지 담보하지는 않습니다.
JSON 스키마 생성기

JSON을 붙여넣으면 브라우저에서 즉시 Draft-07 스키마를 만들어 주며, 입력한 데이터는 서버로 전송되지 않습니다.

자주 묻는 질문

우편번호처럼 숫자로만 이뤄진 값은 스키마에서 어떻게 표시되나요?

값을 따옴표로 감쌌는지가 유일한 기준입니다. "06236"처럼 따옴표 안에 있으면 문자열로 판정되어 { "type": "string" }이 됩니다.

따옴표 없이 06236처럼 적으면 애초에 유효한 JSON 숫자가 아니어서(0으로 시작하는 숫자는 JSON 문법 오류입니다) 파싱 단계에서 오류가 표시됩니다.

배열 안에 서로 다른 타입의 값이 섞여 있으면 어떻게 되나요?

배열 원소의 타입이 여러 종류이면 타입별로 하나씩 예시를 뽑아 각각의 스키마를 만들고, items 안에 anyOf 배열로 묶어 나열합니다.

예를 들어 배열에 숫자·문자열·불리언이 섞여 있으면 anyOf에 세 개의 타입 스키마가 나란히 들어갑니다.

'모든 속성을 필수로 설정' 체크박스는 정확히 무엇을 바꾸나요?

체크하면 각 객체 노드마다 그 객체가 가진 모든 키 이름을 required 배열에 그대로 넣습니다.

일부 키만 선택적으로 골라 넣는 기능은 아니며, 체크를 해제하면 어떤 객체에도 required 배열 자체가 생기지 않습니다.

생성된 스키마 하나로 실제 데이터를 전부 검증할 수 있나요?

생성된 스키마는 입력창에 붙여넣은 JSON 예시 하나를 분석한 결과입니다. 같은 필드가 실제 데이터에서는 다른 타입으로 오거나, 예시에 없던 필드가 추가로 존재할 수 있습니다.

따라서 스키마가 실제 데이터의 모든 경우를 자동으로 담보하지는 않습니다. 여러 상황을 포괄하는 스키마가 필요하다면 대표성 있는 예시 여러 개를 각각 넣어보고 결과를 비교하는 방법이 있습니다.

가격 보기카톡 무료 상담