응답 A
응답 B

API 응답 비교: JSON API 페이로드를 온라인에서 비교

왼쪽에 기대했던 응답을, 오른쪽에 실제로 받은 응답을 붙여넣으면 변경된 모든 필드를 확인할 수 있습니다. 백엔드, QA, 통합 작업을 위해 만들어졌습니다. 브라우저 밖으로 데이터가 나가지 않습니다.

이 API 응답 비교 도구에 대하여

두 개의 HTTP API 응답 본문을 비교하는 무료 브라우저 내 도구입니다. 왼쪽에 staging에서 받은 JSON, 오른쪽에 production에서 받은 JSON을 붙여넣으면 차이점이 글자 단위로 강조됩니다. 텍스트는 절대 사용자의 기기를 떠나지 않습니다. 실제 API 응답에는 고객 이메일 주소, 세션 토큰, 내부 사용자 ID 등 외부 diff 사이트에 업로드하고 싶지 않은 정보가 자주 포함되기 때문에 이는 중요합니다.

불안정한 통합 테스트가 CI에서 깨졌고, 노트북에는 정상 응답의 Postman 스크린샷이 있고 빌드 러너의 CI 로그에는 깨진 응답이 있는 그 순간을 위한 도구입니다. 일회성 조사를 위해 전체 Pact contract test를 띄우는 것은 과합니다. 텍스트 패널 두 개와 diff 하나면 보통 1분 안에 단일 필드까지 좁혀낼 수 있습니다.

내부적으로 diff 엔진은 compare-json 도구를 구동하는 것과 같습니다. API 테스트 워크플로에 맞게 포장만 다릅니다. 응답이 XML이나 SOAP 엔벨로프라면 compare-xml 페이지가 처리합니다. webhook 로그나 감사 추적 같은 자유 형식 텍스트를 비교한다면 compare-text 도구가 올바른 입구입니다.

API 응답 비교가 실제로 도움이 되는 방식

API 응답 비교는 관련은 있지만 별개인 두 가지 테스트 개념 사이의 틈에 있습니다. OpenAPI 3.1 스키마 diff는 계약이 무엇이 바뀌었다고 말하는지 알려줍니다. 새로운 선택 필드, 이름이 바뀐 속성, 더 엄격해진 enum 등. 스냅샷 테스팅(Jest snapshots, Vitest snapshots, pytest-snapshot)은 코드가 저장된 fixture 대비 무엇을 만들어냈는지 알려줍니다. 이 도구는 런타임 쪽에 위치합니다. 실제 응답 본문 두 개를 주면, 스키마가 그 변경을 허용하든 말든, 스냅샷 fixture가 최신이든 아니든 관계없이 다른 모든 바이트를 보여줍니다.

왜 유용할까요? REST 통합 작업에서 가장 아픈 버그는 스키마 위반이 아니기 때문입니다. 미묘한 드리프트입니다. Jackson 업그레이드 후 시리얼라이저가 슬그머니 날짜를 ISO-8601에서 Unix 타임스탬프로 바꿨다, Marshmallow 스키마가 누락된 필드를 생략하는 대신 null을 내보내기 시작했다, 미들웨어 변경 후 DRF ViewSet이 페이로드를 data 엔벨로프로 감싸기 시작했다. OpenAPI 명세는 변하지 않았다. 스냅샷은 갱신되지 않았다. 테스트는 단독으로 통과했다. 통합은 깨졌다. 응답 본문 diff는 이런 모든 경우를 잡아냅니다. 계약을 신경 쓰지 않고 바이트를 신경 쓰기 때문입니다.

휘발성 필드가 가장 주의할 부분입니다. 타임스탬프, request ID, trace ID, 서버 생성 UUID, 페이지네이션 커서는 같은 endpoint를 두 번 캡처해도 의미 있는 변화가 전혀 없을 때조차 다릅니다. 올바른 행동은 비교 전에 정규화하는 것입니다. 타임스탬프를 플레이스홀더로 치환하고, trace ID를 제거하고, 계약상 순서가 중요하지 않은 배열을 정렬합니다. Pact 같은 도구는 matcher로 처리하지만, 이 도구에서는 패널을 편집해 처리합니다. 10초면 끝나고 노이즈 플로어가 사라집니다.

세 단계로 API 응답을 비교하는 방법

텍스트 패널 두 개, diff 하나. 로그인 없음, 업로드 없음, 프록시 배선 없음.

  1. 1

    첫 번째 응답 캡처

    curl, httpie, Postman, Insomnia, 팀에서 사용하는 무엇으로든 endpoint를 호출합니다. curl -s https://api.example.com/v1/users/123 | jq가 좋은 기본형입니다. jq가 JSON을 보기 좋게 정렬해주어 diff 가독성이 훨씬 높아집니다. 본문(헤더 말고 JSON만)을 복사해 왼쪽 패널에 붙여넣습니다. CI 로그에서 가져오는 경우 대부분의 로거가 붙이는 타임스탬프 접두사를 제거해 diff가 실제 페이로드에 떨어지도록 합니다.

  2. 2

    두 번째 응답 캡처

    비교 대상을 호출합니다. 다른 환경, 다른 API 버전, 다른 벤더. 같은 형태의 캡처, 같은 pretty-print 단계. 오른쪽 패널에 붙여넣습니다. 한쪽이 녹화된 fixture(vcrpy, pollyjs, MSW, nock)이고 다른 쪽이 라이브라면 명백한 휘발성 필드를 먼저 정규화합니다. request_id를 지우고, 타임스탬프를 상수로 바꾸고, 본문에 새어 든 trace 헤더를 제거합니다. 남는 diff가 실제 신호입니다.

  3. 3

    강조된 차이점 읽기

    삭제는 왼쪽에 빨간 취소선으로, 추가는 오른쪽에 초록색으로 표시됩니다. 각 헤더의 변경 카운터는 diff가 찾은 별개 편집 수를 알려줍니다. 먼저 세 가지에 집중합니다. status 문자열 변경, 누락되거나 추가된 키, 값 타입 변경(string에서 number로, object에서 null로). 이 세 카테고리가 거의 모든 실제 API 회귀를 커버합니다. 포맷과 순서 변경은 컨슈머가 거기에 의존하지 않는 한 보통 노이즈입니다.

API 응답 비교가 정답인 상황

불안정한 통합 테스트 재현

로컬에서는 통과하는데 CI에서 깨지는 테스트. 로컬 Postman으로 캡처한 응답과 CI 빌드 에이전트가 캡처한 응답이 있습니다(대부분의 CI 시스템은 verbose 플래그로 request/response를 덤프할 수 있습니다). 둘 다 diff 도구에 붙여넣습니다. 열에 아홉은 환경 요인입니다. 다른 feature flag, 오래된 fixture, 빌드 러너의 시간대 오프셋. 나머지 한 번은 진짜 버그이고, 특정 필드까지 좁혀진 상태입니다.

신선한 응답 대비 fixture 검증

리포에는 테스트용으로 서드파티 API를 모킹하는 커밋된 fixture 파일이 있습니다. 업스트림 공급자가 방금 새 마이너 버전을 배포했습니다. curl로 라이브 endpoint를 호출하고 그 응답을 fixture 옆에 붙여넣으면 어떤 필드가 드리프트했는지 정확히 보입니다. VCR 스타일 재생 도구가 자동화하는 작업의 수동 버전입니다. 전체 테스트 스위트를 다시 녹화하지 않고 fixture 하나를 갱신하고 싶을 때 유용합니다.

API 버전의 하위 호환성 확인

내부 API의 v2를 곧 출시합니다. v1 클라이언트가 운영에 아직 존재합니다. /v1/orders/42/v2/orders/42 둘 다 호출해 응답 diff를 봅니다. 제거된 필드, 이름이 바뀐 키, 값 타입 변경은 모두 v1 클라이언트에는 깨짐 변경입니다. 새 필드는 모두 추가형이며 안전합니다. 이는 consumer-driven contract test의 가난한 자의 버전입니다. 수십 개 endpoint로는 확장되지 않지만 한두 개에 대한 빠른 점검에는 잘 통합니다.

시리얼라이저 회귀 포착

Jackson, Marshmallow, DRF 또는 비슷한 시리얼라이저 계층을 업그레이드한 팀. 테스트는 통과합니다. 그런데 다운스트림 컨슈머가 파서가 막혔다고 보고합니다. 같은 endpoint 응답을 이전 브랜치와 새 브랜치에서 캡처해 diff를 봅니다. 흔한 발견은 날짜 포맷이 2026-05-09T10:00:00Z에서 Unix 타임스탬프로 바뀜, 소수점 끝의 0이 사라짐, enum이 string 대신 integer로 시리얼라이즈되기 시작, 이전에는 생략되던 null 필드가 페이로드에 나타나기 시작 등입니다.

두 공급자 또는 버전의 webhook 페이로드 비교

같은 이벤트 타입의 Stripe webhook V1과 V2는 거의 동일해 보이지만 전혀 그렇지 않습니다. GitHub의 webhook 이벤트 페이로드도 API 버전 간에 마찬가지이고, Slack 이벤트 구독도 스코프 간에 마찬가지입니다. 각각의 샘플 페이로드를 diff 도구에 붙여넣어 이름이 바뀐 필드, 이동한 중첩 객체, 새 메타데이터 블록을 봅니다. 두 공급자의 문서 페이지를 나란히 읽는 것보다 빠르고, 특히 문서가 실제로 어떤 필드가 등장하는지 두루뭉술하게 다룰 때 유용합니다.

"staging에서는 되는데 prod에서 깨진다" 디버깅

배포의 고전적 두통. 같은 클라이언트 요청이 staging과 production에서 미묘하게 다른 JSON을 반환합니다. 둘 다 캡처하고 둘 다 붙여넣으면 차이는 보통 설정 플래그, 누락된 feature gate, 또는 오래된 캐시된 응답입니다. 다중 리전 디버깅(us-east-1과 eu-west-1이 다른 데이터를 반환), CDN 캐시 문제(Cloudflare가 오래된 본문을 캐시), 쓰기가 모든 곳에 전파되지 않은 read replica 지연에도 똑같이 적용됩니다.

알아둘 만한 API 응답 비교의 엣지 케이스

응답 본문 diff가 테스트 프레임워크, OpenAPI 도구, 또는 당신의 눈이 말하는 것과 어긋나는 경우들. diff가 진짜 버그를 찾았다고 가정하기 전에 훑어볼 가치가 있습니다.

TopicWhat this tool does
휘발성 필드(타임스탬프, ID)created_at, updated_at, request_id, trace_id, 서버 생성 UUID, 페이지네이션 커서는 두 캡처 사이에 항상 다릅니다. jq 'del(...)'로 정규화하거나 상수로 치환하거나 비교 전에 그냥 편집해 제거하세요. 실제로 신경 써야 할 신호는 다른 곳에 있습니다.
null vs 키 없음{"foo": null}{}는 JSON에서 다릅니다. 많은 시리얼라이저(Marshmallow, Jackson, System.Text.Json)에는 둘을 오가는 설정이 있습니다. diff가 이를 드러냅니다. 어떤 클라이언트는 둘을 동등하게 다루고 어떤 클라이언트는 그렇지 않습니다. 정답은 컨슈머가 무엇을 하느냐이며, 그래서 시리얼라이저 업그레이드 후 자주 발생하는 회귀의 근원입니다.
키 순서RFC 8259는 JSON 객체를 순서 없음으로 정의합니다. 의미적으로 동일하지만 키 순서가 다른 두 응답은 텍스트 비교가 순서에 민감하기 때문에 여기서 diff로 보입니다. 순서에 둔감한 비교를 원한다면 양쪽을 jq --sort-keys로 사전 정렬하세요. 순서에 의존하는 드문 컨슈머(일부 서명 흐름, 일부 레거시 파서)에 주의하세요.
배열 순서JSON의 배열은 순서가 있지만, 많은 API는 실제로 계약상 순서가 없는 배열을 반환합니다. 권한 목록, feature flag 목록, webhook 구독 목록. diff는 재정렬된 배열을 변경으로 표시하지만 어떤 컨슈머도 신경 쓰지 않을 수 있습니다. 도메인에서 재정렬이 무해하면 비교 전에 양쪽을 안정적인 키로 정렬하세요.
JSON.parse 엄격성diff는 입력을 불투명한 텍스트로 다룹니다. 한쪽 캡처에 후행 쉼표, 인용 부호 없는 키, 주석(엄격 JSON에서는 모두 불법)이 있어도 diff는 동작하지만 필요 이상으로 시끄러워 보입니다. 두 캡처를 먼저 jq .에 통과시켜 재포매팅하고 잘못된 입력을 거부하세요. jq는 엄격한 RFC 8259 파서를 사용합니다.
응답 래핑(data 엔벨로프 vs 평탄)많은 API가 페이로드를 {"data": ...} 엔벨로프로 감싸고, 옆에 meta, links, included를 함께 붙이기도 합니다(JSON:API 등). 평탄에서 래핑(또는 그 반대)으로의 마이그레이션은 깨짐 변경이며 diff에 즉시 나타나지만, 내부 레코드는 동일해 보이기 때문에 스키마 리뷰에서 놓치기 쉽습니다.
페이지네이션 커서 변경커서 기반 페이지네이션은 매 호출마다 바뀌도록 설계된 불투명 토큰(next_cursor, after, page_token)을 사용합니다. 항상 diff로 표시됩니다. 비교 전에 제거하거나 data 배열 내용만 비교하고 페이지네이션 블록은 통째로 무시하세요.
에러 응답 형식에러 본문은 무법지대입니다. 어떤 API는 평탄한 {"error": "..."}를 반환하고, 어떤 API는 type, title, status, detail, instance를 갖춘 RFC 7807 Problem Details를 반환하고, 어떤 API는 벤더 고유의 형태를 반환합니다. 자체 형태에서 RFC 7807로의 마이그레이션은 큰 diff를 만들지만 대부분 개선입니다. 반대 방향의 마이그레이션은 일찍 잡을 가치가 있는 회귀입니다.

API 응답 비교: 자주 묻는 질문

Postman의 내장 diff 기능과 무엇이 다른가요?

Postman에는 Collection Runner 안의 응답 비교 뷰와 개별 응답에 대한 Visualize 기능이 있습니다. 둘 다 Postman 안에 살고 응답이 이미 Postman 히스토리 항목으로 저장돼 있다면 좋습니다. 이 도구는 공급자에 무관합니다. Postman, Insomnia, curl, httpie, CI 로그, Stack Overflow 스니펫, 동료의 Slack 메시지에서 붙여넣을 수 있습니다. 계정도, 워크스페이스도, 동기화도 없습니다. 도구 간 일회성 비교라면 그쪽이 더 빠릅니다. 단일 플랫폼 안에서 팀 공유 API 테스팅을 한다면 Postman의 자체 기능으로 충분합니다.

타임스탬프와 request ID 같은 휘발성 필드는 어떻게 처리하나요?

실용적인 행동은 비교 전에 정규화하는 것입니다. 두 붙여넣기 내용을 패널에 연 다음 휘발성 필드를 직접 편집합니다. 타임스탬프를 상수 문자열로 치환, request_idtrace_id 값 제거, 매 호출마다 바뀌는 페이지네이션 커서 삭제. diff는 남은 차이만 강조하며, 그것이 진짜 중요한 부분입니다. 같은 endpoint를 반복 비교한다면 붙여넣기 전에 응답을 jq의 delete 필터(jq 'del(.meta.request_id)')에 통과시킬 수도 있습니다.

OpenAPI 스키마 diff와 무엇이 다른가요?

스키마 diff는 계약을 비교합니다. POST /orders가 선택 필드 discount_code를 추가했다거나 status enum이 새 값을 얻었다는 것을 알려줍니다. oasdiff나 Spectral 같은 OpenAPI 인식 도구가 이 일을 잘합니다. 이 도구는 실제 응답 본문을 비교합니다. 둘은 보완적입니다. 스키마 diff는 계약 변경을 잡고, 응답 diff는 계약과 현실 사이의 드리프트를 잡습니다. 시리얼라이즈 버그, 환경 불일치, 오래된 fixture는 거기에 숨습니다.

큰 응답도 처리할 수 있나요?

실용적으로는 가능합니다. 정렬된 JSON 기준 양쪽 각각 수천 줄까지는 됩니다. 그 이상이면 의미 정리가 포함된 글자 단위 diff가 느려집니다. 서버가 아니라 브라우저에서 돌기 때문입니다. 매우 큰 페이로드(레코드 1만 건짜리 페이지네이션 덤프 같은 것)에는 응답을 레코드별 또는 최상위 키별로 작은 조각으로 자르고 각각 별도로 비교하는 것이 옳은 접근입니다. 또는 속도 위주라면 커맨드라인에서 jddiff <(jq . a.json) <(jq . b.json)으로 구조적 diff를 돌립니다.

XML이나 SOAP 응답에도 동작하나요?

직접은 안 됩니다. 이 페이지는 JSON에 맞춰져 있습니다. 대부분의 최신 REST와 webhook 페이로드가 JSON입니다. XML, SOAP 엔벨로프, RSS, POM 스타일 설정의 diff가 필요하면 compare-xml 도구가 올바른 입구입니다. 들여쓰기와 namespace 포매팅을 정확히 처리합니다. 헤더와 본문이 섞인 원본 응답이거나 텍스트 평문 API(일부 레거시 시스템은 여전히 text/plain을 반환)라면 구조를 강제하지 않는 compare-text가 일을 합니다.

키 순서를 보존하나요, 정렬하나요?

붙여넣은 키 순서를 보존합니다. JSON 객체는 RFC 8259에 따라 공식적으로 순서 없음이라 의미적으로 동일하지만 키 순서가 다른 두 응답은 이 도구에서 diff로 표시됩니다. 순서를 무시하고 싶다면 양쪽을 먼저 jq --sort-keys 또는 동등한 도구로 정규화합니다. 대부분의 클라이언트는 키 순서에 의존하지 않으므로 정렬된 키 정규화가 응답 비교의 안전한 기본값입니다. 다만 일부 레거시 컨슈머(오래된 XML-JSON 브리지, 특정 전자 서명 흐름)는 순서에 의존한다는 점을 유의하세요.

프라이버시와 API 응답에 그것이 중요한 이유

API 응답 페이로드에는 새어나가서는 안 되는 정보가 자주 들어갑니다. 고객 이메일 주소. 내부 사용자 ID. 세션 토큰. 실수로 본문 필드에 들어간 Auth bearer 토큰. Stripe 고객 ID. webhook 비밀. 이름, 주소, 전화번호 같은 PII 필드. 이 중 하나를 클라우드 호스팅 diff 서비스에 붙여넣는 것 자체가 데이터 처리 이벤트이며, 업계에 따라 SOC 2 통제, GDPR 데이터 처리 계약, 또는 HIPAA Business Associate Agreement를 위반할 수 있습니다. 이 도구는 전적으로 브라우저 안에서 돌아갑니다. 어떤 것도 업로드되지 않고, 로깅되지 않으며, 어떤 외부 서비스로도 전송되지 않습니다. diff, 강조 표시, 렌더링 모두 사용자의 기기에서 실행됩니다. 검증은 직관적입니다. 브라우저 DevTools를 열고 Network 탭으로 전환한 뒤 두 응답을 붙여넣고 지켜보세요. 비교할 때 외부로 나가는 요청이 없습니다. 보다 폭넓은 API 설계와 보안 가이드는 Microsoft의 API design best practices가 든든한 참고가 됩니다.