API-respons-diff: sammenlign JSON-API-payloads online
Indsæt den respons du forventede til venstre, den respons du faktisk fik til højre, og se hvert felt der har ændret sig. Bygget til backend-, QA- og integrationsarbejde. Intet forlader din browser.
Hvad dette API-respons-diff-værktøj er
Et gratis værktøj, der kører i browseren, til at sammenligne to HTTP-API-responsbody. Indsæt JSON fra staging til venstre, JSON fra produktion til højre, og forskellene fremhæves tegn for tegn. Teksten forlader aldrig din maskine, hvilket betyder noget, fordi rigtige API-responser ofte indeholder kunders e-mailadresser, sessions-tokens, interne bruger-ID'er og andet, du ikke vil uploade til en tredjeparts diff-side.
Det er bygget til det øjeblik, hvor en flygtig integrationstest falder i CI, og du har et Postman-skærmbillede af en fungerende respons på din laptop og en CI-log med en ødelagt respons fra build-runneren. At sætte en fuld Pact-contract test op til en engangsundersøgelse er overdrevet. To tekstfelter, en diff, og du kan som regel snævre det ind til ét enkelt felt på under et minut.
Under motorhjelmen er diff-motoren den samme, der driver vores compare-json-værktøj. Vi har bare rammet det ind til API-test-flowet. Hvis dine responser er XML eller SOAP-envelopes, klarer vores compare-xml-side det. Hvis du sammenligner fri tekst som en webhook-log eller et audit trail, er vores compare-text-værktøj det rette sted.
Hvordan en API-respons-diff faktisk hjælper
En API-respons-diff sidder i mellemrummet mellem to beslægtede, men forskellige test-idéer. Schema-diff for OpenAPI 3.1 fortæller dig, hvad din kontrakt siger har ændret sig: et nyt valgfrit felt, en omdøbt property, et strammere enum. Snapshot-test (Jest-snapshots, Vitest-snapshots, pytest-snapshot) fortæller dig, hvad din kode producerede i forhold til en gemt fixture. Dette værktøj sidder på runtime-siden. Du giver det to rigtige responsbody, og det viser dig hver byte, der adskiller sig, uanset om skemaet tillader ændringen, eller om din snapshot-fixture er opdateret.
Hvorfor er det nyttigt? Fordi de bugs, der bider hårdest i REST-integrationsarbejde, ikke er skema-overtrædelser. Det er subtile drifts: en serializer der lydløst skiftede en dato fra ISO-8601 til et Unix-timestamp efter en Jackson-opgradering, et Marshmallow-skema der begyndte at sende null i stedet for at udelade et manglende felt, et DRF ViewSet der efter en middleware-ændring begyndte at pakke payload'en ind i en data-envelope. OpenAPI-specen ændrede sig ikke. Snapshottet blev ikke opdateret. Testene gik igennem isoleret. Integrationen knækkede. En diff på responsbody fanger alle disse, fordi den ikke bekymrer sig om kontrakten; den bekymrer sig om byte.
Volatile felter er det vigtigste at holde øje med. Timestamps, request-ID'er, trace-ID'er, server-genererede UUID'er og pagineringscursorer vil afvige mellem to capture af samme endpoint, selv når intet meningsfuldt har ændret sig. Det rigtige træk er at normalisere før diff: udskift timestamps med en placeholder, fjern trace-ID'er, sortér arrays hvor rækkefølgen ikke er kontraktligt vigtig. Værktøjer som Pact klarer det med matchers; i dette værktøj klarer du det ved at redigere felterne. Det tager ti sekunder og fjerner støjbunden.
Sådan diff'er du en API-respons i tre trin
To tekstfelter, en diff. Ingen login, ingen upload, ingen proxy at tilkoble.
- 1
Fang den første respons
Ram endpointet med curl, httpie, Postman, Insomnia eller hvad dit team bruger. curl -s https://api.example.com/v1/users/123 | jq er et godt udgangspunkt, fordi jq formaterer JSON pænt, hvilket gør diffen meget lettere at læse. Kopiér body (kun JSON, ikke headers) og indsæt i venstre felt. Hvis du trækker fra en CI-log, skal du fjerne timestamp-præfikset, som de fleste loggers tilføjer, så diffen lander på selve payloaden.
- 2
Fang den anden respons
Ram sammenligningskilden: det andet miljø, den anden API-version, den anden leverandør. Samme form for capture, samme pretty-print-trin. Indsæt i højre felt. Hvis ét capture er fra en optaget fixture (vcrpy, pollyjs, MSW, nock) og det andet er live, så normalisér først de åbenlyst volatile felter: skrub request_id, udskift timestamps med en konstant og fjern trace-headers, der er sluppet ind i body. Den resterende diff er det reelle signal.
- 3
Læs de fremhævede forskelle
Sletninger vises som rødt overstreget til venstre; tilføjelser som grønt til højre. Ændringstællerne i hver header siger, hvor mange separate redigeringer diffen fandt. Fokusér først på tre ting: ændringer i status-strenge, manglende eller tilføjede nøgler og ændringer af værditype (string til number, object til null). De tre kategorier dækker næsten enhver reel API-regression. Format- og rækkefølgeændringer er normalt støj, medmindre din consumer afhænger af dem.
Hvornår en API-respons-diff er det rigtige valg
Genskab en flygtig integrationstest
En test går igennem lokalt og falder i CI. Du har responsen, som dit lokale Postman-kørsel fangede, og responsen, som CI-build-agenten fangede (de fleste CI-systemer kan dumpe request/response med et verbose-flag). Indsæt begge i diff-værktøjet. Ni ud af ti gange er forskellen miljørelateret: en anden feature flag, en gammel fixture, en tidszone-offset på runneren. Den tiende er en rigtig bug, og du har lige lokaliseret den til et bestemt felt.
Validér en fixture mod en frisk respons
Dit repo har en indtjekket fixture-fil, der mocker et tredjeparts-API i testene. Upstream-leverandøren udgav lige en ny minor-version. Ram det live endpoint med curl, indsæt den respons ved siden af din fixture, og du ser præcis, hvilke felter der drev. Det er den manuelle udgave af det, VCR-lignende replay-værktøjer automatiserer. Nyttigt når du vil opdatere én fixture uden at genoptage hele testsuiten.
Tjek baglæns kompatibilitet mellem API-versioner
Du er ved at frigive v2 af et internt API. En v1-klient findes stadig i produktion. Ram både /v1/orders/42 og /v2/orders/42 og diff responserne. Ethvert fjernet felt, enhver omdøbt nøgle, enhver ændring af værditype er en breaking change for v1-klienten. Ethvert nyt felt er additivt og sikkert. Det er en fattigmandsudgave af en consumer-driven contract test; den skalerer ikke til dusinvis af endpoints, men til en hurtig sanity check på en eller to virker den.
Find en serializer-regression
Dit team opgraderede Jackson, Marshmallow, DRF eller et lignende serialiseringslag. Testene består. Bagefter melder en downstream-consumer, at deres parser sætter sig fast. Fang samme endpoint-respons på den gamle branch og den nye branch og diff dem. Almindelige fund: et datoformat skiftede fra 2026-05-09T10:00:00Z til et Unix-timestamp, decimaler mistede afsluttende nuller, et enum begyndte at serialisere som integer i stedet for string, eller null-felter dukkede op i payload'en, der tidligere blev udeladt.
Sammenlign webhook-payloads fra to leverandører eller versioner
Stripe-webhook V1 og V2 af samme event-type ser næsten identiske ud og er det slet ikke. Det samme gælder GitHub-webhook-event-payloads mellem API-versioner og Slack-event-subscriptions mellem scopes. Indsæt et eksempel-payload fra hver i diff-værktøjet for at se omdøbte felter, flyttede indlejrede objekter og nye metadata-blokke. Det er hurtigere end at læse begge leverandørers doc-sider side om side, især når dokumentationen glider hen over, hvilke felter der faktisk dukker op i praksis.
Debug klassikeren "virker på staging, ødelagt på prod"
Den klassiske deploy-hovedpine. Samme klient-request returnerer subtilt forskellig JSON fra staging og produktion. Fang begge, indsæt begge, og forskellen er som regel et config-flag, en manglende feature gate eller en gammel cachet respons. Det gælder lige så meget for debugging på tværs af regioner (us-east-1 vs eu-west-1, der returnerer forskellige data), CDN-cacheproblemer (Cloudflare cachede en gammel body) og read-replica-forsinkelse, hvor en skrivning ikke er propageret overalt.
Edge cases for API-respons-diff værd at kende
De tilfælde, hvor en respons-body-diff er uenig med, hvad dit testframework, dit OpenAPI-værktøj eller dine øjne ville sige. Værd at skimme, før du antager, at diffen har fundet en rigtig bug.
| Topic | What this tool does |
|---|
| Volatile felter (timestamps, ID) | created_at, updated_at, request_id, trace_id, server-genererede UUID'er og pagineringscursorer vil altid afvige mellem to capture. Normalisér dem med jq 'del(...)', udskift med en konstant, eller redigér dem ud før diff. Det signal, du faktisk bekymrer dig om, bor et andet sted. |
|---|
| null vs manglende nøgle | {"foo": null} og {} er forskellige i JSON, og mange serializers (Marshmallow, Jackson, System.Text.Json) har indstillinger, der skifter mellem dem. Diffen får det frem. Nogle klienter behandler dem som ækvivalente, andre ikke; det rigtige svar er, hvad din consumer gør, og det er derfor, det er en hyppig regressionskilde efter en serializer-opgradering. |
|---|
| Nøglerækkefølge | RFC 8259 definerer JSON-objekter som uordnede. To semantisk identiske responser med forskellig nøglerækkefølge vises her som diff, fordi tekstsammenligning er rækkefølgefølsom. Sortér begge sider på forhånd med jq --sort-keys, hvis du vil have rækkefølge-uafhængig diff. Pas på den sjældne consumer, der faktisk afhænger af rækkefølge (visse signeringsflows, visse legacy-parsers). |
|---|
| Array-rækkefølge | Arrays i JSON er ordnede, men mange API'er returnerer arrays, hvis rækkefølge faktisk ikke er kontraktlig: en liste over permissions, en liste over feature flags, en liste over webhook-subscriptions. En diff markerer en omsorteret array som ændring, selv når ingen consumer bekymrer sig. Hvis omsortering er harmløs i dit domæne, så sortér begge sider på en stabil nøgle før diff. |
|---|
| JSON.parse-strenghed | Diffen behandler dit input som ugennemsigtig tekst. Har et af dine capture et trailing-komma, en uciteret nøgle eller en kommentar (alle ulovlige i streng JSON), vil den stadig diffe, men se mere støjende ud end nødvendigt. Kør begge capture gennem jq . først for at omformatere og afvise ugyldigt input. jq bruger en streng RFC 8259-parser. |
|---|
| Respons-indpakning (data-envelope vs flad) | Mange API'er pakker payloads ind i en {"data": ...}-envelope, nogle gange med meta, links eller included ved siden af (JSON:API og lignende). En migration fra flad til indpakket (eller omvendt) er en breaking change, der dukker op i en diff med det samme, men er let at overse i en skema-gennemgang, fordi den underliggende record ser ens ud. |
|---|
| Ændringer af pagineringscursor | Cursor-baseret paginering bruger ugennemsigtige tokens (next_cursor, after, page_token), der er designet til at ændre sig ved hvert kald. De vises altid som diff. Fjern dem før sammenligning, eller sammenlign kun indholdet af data-arrayen og ignorér pagineringsblokken helt. |
|---|
| Formater for fejlresponser | Fejl-body er det vilde vesten. Nogle API'er returnerer en flad {"error": "..."}, nogle returnerer RFC 7807 Problem Details med type, title, status, detail, instance, og nogle returnerer en leverandørspecifik form. En migration til RFC 7807 fra en egen form giver en stor diff, der mest er en forbedring; en migration den anden vej er en regression værd at fange tidligt. |
|---|
API-respons-diff: ofte stillede spørgsmål
Hvordan adskiller dette sig fra Postmans indbyggede diff-funktion?
Postman har en respons-sammenligningsvisning inde i Collection Runner og en Visualize-funktion til enkelte responser. Begge er gode, hvis du lever i Postman, og dine responser allerede er gemt som Postman-historik. Dette værktøj er leverandøruafhængigt. Du kan indsætte fra Postman, Insomnia, curl, httpie, en CI-log, et Stack Overflow-snippet eller en kollegas Slack-besked. Ingen konto, ingen workspace, ingen sync. Til engangs-sammenligninger på tværs af værktøjer er det hurtigere. Til team-delte API-tests inden for én platform er Postmans egen funktion fin.
Hvordan håndterer jeg volatile felter som timestamps og request-ID?
Det pragmatiske træk er at normalisere før diff. Åbn begge indsætninger i felterne, og redigér så de volatile felter direkte: udskift timestamps med en konstant streng, fjern værdierne for request_id og trace_id, slet pagineringscursorer, der ændrer sig ved hvert kald. Diffen fremhæver kun de tilbageværende forskelle, og dem er det dem, der faktisk betyder noget. Til gentagne sammenligninger af samme endpoint kan du også sende responsen gennem jq med et delete-filter (jq 'del(.meta.request_id)'), før du indsætter.
Hvordan adskiller dette sig fra en OpenAPI-skema-diff?
Skema-diff sammenligner kontrakter: den fortæller dig, at POST /orders har tilføjet et valgfrit felt discount_code, eller at enumet status har fået en ny værdi. OpenAPI-bevidste værktøjer som oasdiff eller Spectral gør det godt. Dette værktøj sammenligner faktiske responsbody. De to supplerer hinanden. Skema-diff fanger kontraktændringer; respons-diff fanger driften mellem kontrakt og virkelighed, som er der, hvor serialiseringsbugs, miljøforskelle og gamle fixtures gemmer sig.
Kan det håndtere store responser?
I praksis ja, op til et par tusind linjer formateret JSON pr. side. Derudover bliver tegn-diffen med semantisk oprydning langsom, fordi den kører i din browser og ikke på en server. Til meget store payloads (tænk en pagineret dump af 10.000 records) er den rigtige tilgang at skære responsen i mindre stykker pr. record eller pr. top-level-nøgle og diffe hvert stykke separat. Eller køre en strukturel diff fra kommandolinjen med jd eller diff <(jq . a.json) <(jq . b.json) for ren hastighed.
Virker det for XML- eller SOAP-responser?
Ikke direkte. Denne side er trimmet til JSON, som er det, de fleste moderne REST- og webhook-payloads bruger. Hvis du skal diffe XML, SOAP-envelopes, RSS eller POM-lignende konfiguration, er vores compare-xml-værktøj det rette sted; det håndterer indrykning og namespace-formatering korrekt. Til rå responsbody, der blander headers og body, eller til plain-text-API'er (nogle legacy-systemer returnerer stadig text/plain), klarer compare-text opgaven uden at forsøge at påtvinge en struktur.
Bevarer det nøglerækkefølgen eller sorterer det nøglerne?
Det bevarer den nøglerækkefølge, du indsætter. JSON-objekter er formelt uordnede ifølge RFC 8259, så to semantisk identiske responser med nøgler i forskellig rækkefølge vises som diff i dette værktøj. Vil du ignorere rækkefølge, så normalisér begge sider først ved at sende dem gennem jq --sort-keys eller tilsvarende. De fleste klienter afhænger ikke af nøglerækkefølge, så normalisering med sorterede nøgler er en sikker default til respons-sammenligning; vær opmærksom på, at nogle legacy-consumers (ældre XML-til-JSON-broer, visse digitale signaturflows) faktisk er afhængige af rækkefølge.
Privatliv og hvorfor det betyder noget for API-responser
API-respons-payloads indeholder regelmæssigt ting, du ikke vil have lækket. Kunders e-mailadresser. Interne bruger-ID'er. Sessions-tokens. Auth-bearer-tokens, der ved en fejl er endt i et body-felt. Stripe-kunde-ID'er. Webhook-secrets. PII-felter som navne, adresser og telefonnumre. At indsætte en sådan i en cloud-hostet diff-tjeneste er i sig selv en databehandlingsbegivenhed, og afhængigt af din branche kan det krænke dine SOC 2-kontroller, GDPR-databehandlingsaftaler eller HIPAA Business Associate Agreements. Dette værktøj kører helt i din browser. Intet uploades, logges eller sendes til nogen tredjepartstjeneste. Diff, fremhævning og rendering køres alle på din maskine. At verificere påstanden er enkelt: åbn browserens DevTools, skift til Network-fanen, indsæt begge responser og se. Der er ingen udgående requests, når du sammenligner. Til bredere vejledning om API-design og sikkerhed er Microsofts API design best practices en solid reference.