빠른 비교
{ "nickname": null }갈리는 기준
null과 키 부재는 의미가 다르다 — 혼용하면 파싱 코드가 두 경우를 모두 처리해야 한다
{"nickname": null}은 nickname 키가 존재하며 값이 의도적으로 비어 있음을 명시합니다. 반면 {}처럼 키 자체가 없는 경우는 그 필드에 대한 정보가 전달되지 않은 상태입니다. 두 상태를 같은 의미로 처리하면 소비자는 "키가 있는데 null인 경우"와 "키 자체가 없는 경우"를 모두 체크하는 방어 코드를 작성해야 합니다. API 설계 초기에 이 두 상태의 의미를 분리해 문서화하면 소비자 코드의 암묵적 가정을 크게 줄일 수 있습니다.
PATCH API에서 null과 missing은 전혀 다른 명령이다 — 구분하지 않으면 데이터 삭제와 미수정이 섞인다
PATCH 요청에서 {"nickname": null}은 "닉네임을 명시적으로 지운다"는 명령이고, {}는 "닉네임을 건드리지 않는다"는 명령입니다. 이 의미론을 서버가 구분하지 않으면 빈 PATCH 요청이 의도치 않은 필드 초기화를 일으킬 수 있습니다. JSON Merge Patch(RFC 7396)는 이 패턴을 표준화한 것으로, null 값은 해당 키를 삭제하라는 명시적 신호로 정의합니다. 이 표준을 따를지, 도메인 고유 규칙을 만들지와 무관하게, 팀 내 API 문서에 이 두 상태의 의미를 예제와 함께 명시하는 것이 우선입니다.
PATCH 해석 예
{ "nickname": null } → 닉네임을 명시적으로 비운다 (삭제)
{ } → 닉네임을 건드리지 않는다 (유지)JSON Schema에서 required와 nullable은 서로 다른 관심사다
JSON Schema의 required는 키 존재 여부를 검증합니다. required: ["nickname"]이 선언되어 있으면 키 자체가 없으면 검증 실패입니다. 그러나 키가 있고 값이 null이라면 required는 통과합니다. null 허용 여부는 별도로 type: ["string", "null"] 또는 draft 2020-12의 nullable 조합으로 제어해야 합니다. 이 두 개념을 혼동하면 "필드가 required인데 null을 보냈더니 통과됐다"는 당황스러운 상황이 생깁니다.
{
"properties": {
"nickname": { "type": ["string", "null"] }
},
"required": ["nickname"]
}"없음", "알 수 없음", "의도적 초기화"를 한 값으로 표현하면 소비자마다 해석이 달라진다
좋은 API는 null 하나로 여러 의미를 뭉개지 않습니다. 예를 들어 null이 "데이터가 아직 수집되지 않음"인지, "의도적으로 값을 없앤 것"인지, "해당 없음"인지를 구분하려면 별도 필드나 enum 값을 사용하는 것이 더 명확합니다. GraphQL API에서 null과 필드 부재를 명확히 구분하는 설계가 있는 이유도 여기에 있습니다. 이 구분이 과도하다면 최소한 null의 의미를 API 문서에 하나로 고정해야 합니다.
{ "nickname": null }선택 기준
| 상황 | 적합한 선택 |
|---|---|
| 값이 의도적으로 없음을 전달 | null (키는 포함) |
| 필드를 수정하지 않겠다는 PATCH 요청 | 키 자체를 생략 |
| 키 존재 여부 검증 | JSON Schema required |
| null 허용 여부 검증 | type: ["string", "null"] |
| "모름", "해당 없음", "삭제"를 구분해야 할 때 | enum 또는 별도 상태 필드 고려 |
주의할 점
null과 키 부재를 같은 의미로 문서화하지 않으면 소비자마다 다른 해석을 합니다. 특히
PATCH API에서는 null이 "삭제"이고 키 생략이 "유지"인 패턴이 흔하므로, 이 의미론을
예제와 함께 명시적으로 문서화해야 합니다. JSON Schema의 required는 키 존재 여부만
검사하므로, null 허용 여부는 type 규칙으로 별도 선언해야 합니다.
{}null과 키 생략을 같은 의미로 처리하면, PATCH에서 "삭제"와 "유지"를 분리할 수 없게 됩니다. 이 차이는 초반에 문서로 고정해 두는 편이 좋습니다.
응답 설계에서도 마찬가지입니다. nickname: null이 "아직 모름"인지 "일부러 비움"인지 문서가 없으면 소비자마다 다른 화면과 저장 로직이 생깁니다.
참고 링크
2 sources