alltools.one
JSON
2025-06-24
7 min
alltools.one Team
JSONDiffDebuggingAPITesting

JSON Diff 디버깅 가이드: 복잡한 데이터에서 변경 찾기

표준 텍스트 diff 도구는 JSON에 잘 작동하지 않습니다. 키 재정렬, 공백 변경, 깊은 중첩이 실제 데이터 변경을 가리는 노이즈 많은 diff를 만듭니다. 구조적 JSON diff는 텍스트 표현이 아닌 의미론, 즉 실제 데이터를 비교합니다. 이 가이드에서는 효과적인 JSON 비교와 디버깅 기법을 다룹니다.

표준 Diff가 JSON에 실패하는 이유

의미론적으로 동일한 두 JSON 객체를 고려하세요:

버전 A:

{"name":"Alice","age":30,"roles":["admin","editor"]}

버전 B:

{
  "age": 30,
  "name": "Alice",
  "roles": ["admin", "editor"]
}

텍스트 diff는 모든 줄이 변경된 것으로 표시하지만, 데이터는 동일합니다. 구조적 diff는 같다는 것을 인식합니다.

이제 실제 변경을 고려하세요:

// 이전
{ "user": { "name": "Alice", "permissions": ["read", "write", "admin"] } }

// 이후
{ "user": { "name": "Alice", "permissions": ["read", "write"] } }

구조적 diff는 보고합니다: removed user.permissions[2]: "admin" — 정확히 필요한 정보.

JSON Diff 도구로 즉시 시도해보세요.

JSON 변경 유형

구조적 JSON diff는 변경을 다음으로 분류합니다:

변경 유형예시
추가됨새 키 또는 배열 요소
제거됨누락된 키 또는 배열 요소
수정됨기존 키의 값 변경
타입 변경값 타입 변경 (문자열 → 숫자)
이동됨배열 요소 순서 변경

커맨드 라인 JSON Diff

jq로 빠른 비교

# 키 정렬 후 비교
diff <(jq -S . before.json) <(jq -S . after.json)

# 특정 경로 비교
diff <(jq '.config.database' before.json) <(jq '.config.database' after.json)

전문 도구

# json-diff (npm)
npx json-diff before.json after.json

# jd (Go)
jd before.json after.json

API 응답 변경 디버깅

API 응답이 예기치 않게 변경될 때, 체계적 비교가 근본 원인을 식별하는 데 도움을 줍니다:

1단계: 기준선 캡처

알려진 정상 응답을 저장합니다:

curl -s https://api.example.com/users/123 | jq -S . > baseline.json

2단계: 현재 캡처

curl -s https://api.example.com/users/123 | jq -S . > current.json

3단계: 구조적 Diff

# 사람이 읽기 쉬운 형태
npx json-diff baseline.json current.json

# 기계가 읽기 쉬운 형태 (JSON Patch 포맷)
npx json-diff baseline.json current.json --json

4단계: 노이즈 필터링

요청마다 변경되는 필드(타임스탬프, 요청 ID)를 제외합니다:

# 비교 전 변동 필드 제거
jq 'del(.meta.requestId, .meta.timestamp)' response.json

JSON Patch (RFC 6902)

JSON Patch는 JSON 문서의 변경을 설명하는 표준화된 포맷입니다:

[
  { "op": "replace", "path": "/user/name", "value": "Bob" },
  { "op": "remove", "path": "/user/permissions/2" },
  { "op": "add", "path": "/user/email", "value": "bob@example.com" }
]

연산:

  • add: 새 값 추가
  • remove: 값 제거
  • replace: 기존 값 변경
  • move: 새 경로로 값 이동
  • copy: 새 경로로 값 복사
  • test: 값의 존재 확인 (조건부 패치용)

JSON Patch는 전체 문서를 교체하는 대신 API에 점진적 업데이트를 보내는 데 유용합니다.

설정 드리프트 감지

시간에 따른 설정 파일 변경을 추적합니다:

#!/bin/bash
# drift-check.sh
BASELINE="config-baseline.json"
CURRENT="config-current.json"

DIFF=$(npx json-diff "$BASELINE" "$CURRENT" 2>/dev/null)

if [ -n "$DIFF" ]; then
  echo "설정 드리프트 감지됨:"
  echo "$DIFF"
  exit 1
fi

echo "드리프트가 감지되지 않았습니다."

테스트에서의 JSON Diff

API 응답을 검증하기 위해 테스트에서 구조적 비교를 사용합니다:

const { diff } = require('json-diff');

test('API 응답이 예상 구조와 일치', async () => {
  const response = await fetch('/api/users/123');
  const data = await response.json();
  
  const expected = {
    id: 123,
    name: 'Alice',
    role: 'admin'
  };
  
  const changes = diff(expected, data);
  expect(changes).toBeUndefined(); // undefined는 동일함을 의미
});

대용량 JSON 파일 처리

수 메가바이트의 JSON 파일에서는 시각적 diff가 비실용적입니다:

  1. 먼저 쿼리: diff 전에 관련 섹션을 추출하기 위해 JSONPath를 사용하세요. JSONPath 가이드를 참조하세요.
  2. 요약 모드: 모든 변경을 보여주는 대신 유형별 변경 수를 세세요
  3. 스트리밍 diff: jd 같은 도구는 스트리밍으로 대용량 파일을 효율적으로 처리합니다
# 특정 섹션을 추출하여 비교
jq '.data.users[:10]' large-before.json > section-before.json
jq '.data.users[:10]' large-after.json > section-after.json
npx json-diff section-before.json section-after.json

자주 묻는 질문

JSON Patch와 JSON Merge Patch 중 어떤 것을 사용해야 하나요?

JSON Patch (RFC 6902)는 연산 배열을 사용하며 배열 요소 조작을 포함한 모든 변경을 표현할 수 있습니다. JSON Merge Patch (RFC 7396)는 더 간단합니다 — 부분 JSON 객체를 보내면 대상과 병합됩니다. 간단한 객체 업데이트에는 Merge Patch를, 배열 조작이나 원자적 연산이 필요할 때는 JSON Patch를 사용하세요.

키 순서가 다른 JSON을 어떻게 diff하나요?

대부분의 구조적 JSON diff 도구는 키 순서를 무의미하게 취급합니다 — {"a":1,"b":2}{"b":2,"a":1}와 같습니다. 텍스트 기반 도구에는 jq -S .로 먼저 정규화하여 키를 알파벳순으로 정렬하세요. JSON Diff 도구는 키 순서를 자동으로 처리합니다.

관련 리소스

Published on 2025-06-24
JSON Diff Debugging Guide: Find Changes in Complex Data | alltools.one