본문 바로가기
C.W.K.
Stream
Lesson 06 of 08 · published

조합 — allOf, oneOf, anyOf, not

~12 min · json-schema, composition, polymorphism

Level 0평문
0 XP0/64 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete

실세계 모양 모델링하기 위한 schema 조합

allOf — 교집합

주어진 값이 모든 sub-schema 를 다 통과해야 해. 상속처럼 쌓아 올릴 때 써. 'Base 이면서 이 필드들도 더 갖는다' 같은 거지.

anyOf — 합집합 (최소 하나)

sub-schema 중 하나만 통과해도 돼. 경계가 느슨한 합집합에 써. 'string 이거나 number', '이 여러 모양 중 아무거나' 같은 경우야.

oneOf — 배타적 합집합 (정확히 하나)

딱 하나의 sub-schema 에만 맞아야 해. tagged union 이 여기 딱이야. '신용카드 정보가 든 결제이거나 계좌이체 정보가 든 결제이거나, 둘 다는 아니고' 처럼.

not — 부정

이 sub-schema 에 맞으면 안 된다는 뜻이야. 되도록 아껴 써. not 이 뱉는 에러 메시지가 모호하기로 악명 높거든. 가능하면 '아니어야 한다' 대신 '이러이러해야 한다' 로 뒤집어 써.

Tagged-union 패턴: 모양이 여럿인 데이터 ('N 가지 중 하나') 는 const 로 고정한 구분 필드 (kind, type) 를 넣고 oneOf 로 묶는 게 좋아. 그래야 validator 가 어느 하나에 걸렸을 때 에러 메시지가 또렷하게 나와. anyOf 로 두면 사용자가 어느 쪽을 의도했는지 validator 도 모르고, 그래서 에러도 흐릿해져.

Code

allOf — 추가 사항 가진 base 조합·json
{
  "$defs": {
    "Identifiable": {
      "type": "object",
      "properties": { "id": { "type": "integer" } },
      "required": ["id"]
    }
  },
  "allOf": [
    { "$ref": "#/$defs/Identifiable" },
    {
      "type": "object",
      "properties": {
        "name": { "type": "string" }
      },
      "required": ["name"]
    }
  ]
}
oneOf — tagged union (깨끗한 에러)·json
{
  "oneOf": [
    {
      "type": "object",
      "properties": {
        "kind":       { "const": "credit_card" },
        "card_last4": { "type": "string", "pattern": "^[0-9]{4}$" }
      },
      "required": ["kind", "card_last4"]
    },
    {
      "type": "object",
      "properties": {
        "kind":          { "const": "bank_transfer" },
        "routing_number": { "type": "string" },
        "account_last4":  { "type": "string", "pattern": "^[0-9]{4}$" }
      },
      "required": ["kind", "routing_number", "account_last4"]
    }
  ]
}
anyOf — string 또는 string 형태 number·json
{
  "properties": {
    "id": {
      "anyOf": [
        { "type": "integer" },
        { "type": "string", "pattern": "^[0-9]+$" }
      ]
    }
  }
}

External links

Exercise

'결제 방식' 을 세 갈래 (credit_card / bank_transfer / wallet) 짜리 oneOf 로 짜봐. 갈래마다 자기 필수 필드를 두고, 공통으로 kind 구분 필드를 넣어. 종류별로 문서를 하나씩 만들어 검증하고, 마지막으로 두 종류의 필드를 뒤섞은 문서를 만들어봐. validator 가 거부할 거야. 어느 가지에도 정확히 하나로 맞아떨어지지 않으니까.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.