핵심 정리
{
"type": "object",
"properties": {
"shippingAddress": { "$ref": "#/$defs/address" },
"billingAddress": { "$ref": "#/$defs/address" }
},
"$defs": {
"address": {
"type": "object",
"properties": {
"city": { "type": "string" },
"zip": { "type": "string" }
},
"required": ["city", "zip"]
}
}
}참조 방식
$defs는 현재 schema 안에서 재사용할 조각을 두는 곳이다
같은 object 구조가 여러 위치에서 반복되면 schema가 길어지고 수정 누락이 생깁니다. $defs에 공통 조각을 이름 붙여 두고 필요한 위치에서 $ref로 참조하면 중복을 줄일 수 있습니다.
{
"$defs": {
"name": {
"type": "string",
"minLength": 1
}
},
"type": "object",
"properties": {
"firstName": { "$ref": "#/$defs/name" },
"lastName": { "$ref": "#/$defs/name" }
}
}#/$defs/name은 현재 schema 문서 안의 $defs.name 위치를 가리키는 JSON Pointer입니다. 현재 문서 안에서만 쓰는 작은 재사용 조각이라면 별도 파일로 나누기보다 $defs가 읽기 쉽습니다.
$ref는 schema를 복사하는 것이 아니라 해당 schema를 적용한다
$ref는 참조 대상 schema를 찾아 그 위치의 instance에 적용합니다. 단순 text include가 아니라 resolver가 URI와 JSON Pointer를 해석합니다. 그래서 내부 참조, 외부 파일 참조, 절대 URI 참조를 구분해서 관리해야 합니다.
{
"$id": "https://example.com/schemas/order",
"type": "object",
"properties": {
"customer": { "$ref": "https://example.com/schemas/customer" },
"items": {
"type": "array",
"items": { "$ref": "#/$defs/orderItem" }
}
},
"$defs": {
"orderItem": {
"type": "object",
"required": ["sku", "quantity"]
}
}
}외부 참조가 많아지면 validator 설정, 네트워크 접근, bundling 방식까지 같이 정해야 합니다. 배포 단순성이 중요하면 schema bundle을 만들어 한 파일로 배포하는 방식도 고려합니다.
$id가 상대 참조의 기준 URI가 된다
상대 $ref는 기준 URI를 기준으로 해석됩니다. schema에 $id가 없거나 익명 schema로 전달되면 상대 참조를 해석하지 못할 수 있습니다. 외부 참조를 쓰는 schema에는 $id를 명시해 기준을 고정하는 편이 안전합니다.
{
"$id": "https://example.com/schemas/customer",
"type": "object",
"properties": {
"address": { "$ref": "/schemas/address" }
}
}위 예시에서 /schemas/address는 $id의 기준 URI와 결합되어 https://example.com/schemas/address로 해석됩니다. $id가 없는 익명 schema라면 같은 상대 참조가 실패할 수 있습니다.
선택 기준
| 상황 | 선택 |
|---|---|
| 같은 schema 조각을 현재 파일 안에서 반복 | $defs + 내부 $ref |
| 여러 schema 파일에서 공유 | 외부 schema + 절대 URI $ref |
| validator 배포를 단순하게 유지 | bundle 생성 고려 |
| 재귀 구조 표현 | 자기 자신 또는 내부 $defs 참조 |
| 상대 참조 사용 | $id로 기준 URI 고정 |
주의사항
상대 $ref는 기준 URI가 있어야 안정적으로 해석됩니다. 익명 schema에 상대 참조를 넣으면 validator 환경에 따라 해석이 실패할 수 있습니다.
{
"properties": {
"address": { "$ref": "/schemas/address" }
}
}외부 참조를 쓴다면 $id를 함께 선언해서 기준을 명확히 두세요.
서로를 계속 참조하는 $ref 순환은 resolver를 막히게 만들 수 있습니다. 트리처럼 자기 자신을 재귀 참조하는 구조와, 두 정의가 끝없이 서로만 가리키는 구조를 구분해야 합니다.
참고 링크
1 sources