Compararea a două structuri JSON
- Panou de control
- Documentație
- API
De ce să compari două JSON-uri?
Compararea a două structuri JSON revine în mod regulat în viața unui dezvoltator. Un răspuns API care se schimbă după o actualizare. Un fișier de configurare care diverge între două medii. Un export de obiecte care trebuie să se alinieze pe o referință. Un diff JSON răspunde exact acestei întrebări: ce a fost adăugat, șters sau modificat, și unde?
Un diff linie cu linie (de tip git diff) adesea nu este suficient. Dacă formatarea
diferă (spații, ordinea cheilor), diff-ul textual semnalează sute de linii deși structura
datelor este identică. Un comparator JSON lucrează pe structură odată parsată, ceea ce elimină acest
zgomot și relevă doar diferențele semantice.
Formatul diff-ului produs de instrument
Pentru fiecare diferență, instrumentul returnează:
- un cale în format JSONPath simplificat, de exemplu
$.user.address[0].city; - un tip printre added (adăugat la dreapta), removed (prezent la stânga doar), modified (valori diferite);
- valoarea din stânga și/sau valoarea din dreapta în funcție de tip.
Un diff gol înseamnă că cele două JSON-uri sunt structural identice, independent de formatarea lor sau de ordinea cheilor.
Cum parcurge algoritmul cele două structuri
Algoritmul este recursiv. La fiecare nivel, identifică tipul celor două valori comparate:
- Dacă ambele sunt obiecte asociative, ia uniunea cheilor. Pentru fiecare cheie, coboară recursiv, sau marchează added/removed dacă cheia nu există decât pe o parte.
- Dacă ambele sunt tablouri ordonate, compară poziție cu poziție. O diferență la începutul tabloului poate decala tot restul, ceea ce produce un diff verbos: este o limită asumată a diff-ului structural naiv.
- Dacă tipurile diferă (obiect față de tablou, scalar față de null), este marcat modified.
- Dacă cele două valori sunt scalare (șir, număr, boolean, null), o simplă comparație strictă este suficientă.
Ordinea cheilor într-un obiect nu contează: {"a": 1, "b": 2} și {"b": 2, "a": 1}
produc un diff gol. Este conform cu semantica JSON, unde ordinea nu este semnificativă. În
schimb, ordinea elementelor unui tablou contează: un tablou este ordonat prin construcție.
Un exemplu concret
Iată două versiuni ale unui obiect utilizator:
// stânga
{
"id": 42,
"name": "Alice",
"roles": ["admin", "editor"]
}
// dreapta
{
"id": 42,
"name": "Alice Martin",
"roles": ["admin", "viewer"],
"active": true
}
Diff-ul produs:
$.name: modified,"Alice"→"Alice Martin"$.roles[1]: modified,"editor"→"viewer"$.active: added,true
Cazuri de utilizare
- Diff de medii: a compara ieșirea unui endpoint în pre-producție și producție. Foarte util în timpul unei migrări sau a unei reîmprospătări de cache.
- Audit de migrare: a compara un export înainte și după transformare pentru a verifica că niciun câmp nu a fost pierdut.
- Regresie API: înainte și după o modificare, a compara răspunsul pentru o cerere identică. Un diff gol confirmă non-regresia.
- Sincronizare de configurări: a compara
composer.jsonîntre două ramuri, două fișiere.eslintrc, două configurări Symfony. - Snapshot tests: a înlocui o comparație linie cu linie cu o comparație structurală într-o suită de teste de integrare.
Limitele diff-ului structural
Compararea tablourilor ordonate este o limită cunoscută a diff-urilor structurale naive. Dacă se inserează un element la începutul unui tablou, toate pozițiile următoare sunt decalate și diff-ul semnalează fiecare diferență ca o modificare. Pentru astfel de cazuri, algoritmi mai avansați există (Myers, Patience, diff prin cheie naturală), dar ies din cadrul unui instrument de comparație generalist.
Diff-ul nu spune nici de ce s-a întâmplat o schimbare: este o constatare. Pentru a analiza o regresie, trebuie încrucișată această constatare cu commit-urile, deploy-urile și parametrii cererii.
JSON diff vs JSON Patch (RFC 6902)
Un format complementar este JSON Patch (RFC 6902). Descrie, sub formă de operații
(add, remove, replace, move, copy,
test), cum să transformi un document JSON în altul. Acolo unde diff-ul nostru este o constatare
(umană), JSON Patch este o rețetă (mașină). Cele două reprezentări sunt echivalente pentru
cazurile simple, iar JSON Patch este util pentru API-uri RESTful care acceptă modificări
parțiale.
Întrebări frecvente
Depinde diff-ul de ordinea cheilor?
Nu: pentru un obiect JSON, ordinea nu este semnificativă. Comparatorul produce același rezultat indiferent dacă cheile sunt sortate sau nu.
Cum să gestionez tablourile a căror ordine nu este importantă?
Instrumentul consideră implicit tablourile ca ordonate (este semantica JSON). Dacă tratezi mulțimi, sortează cele două tablouri după o cheie naturală înainte de a compara, sau utilizează un serviciu de comparație specializat care ia în considerare această semantică.
Care este diferența cu un diff Git?
Git compară linii de text. Dacă indentarea sau ordinea cheilor diferă, diff-ul Git este foarte verbos. Diff-ul JSON lucrează pe structura parsată și nu semnalează decât diferențele de date.
Este un JSON invalid acceptat?
Nu: dacă unul dintre cele două JSON-uri nu se parsează, instrumentul returnează o eroare. Validează mai întâi cu validatorul nostru JSON.
Exemplu de cerere
curl -X POST https://cdrn.fr/api/v1/tools/json-diff/execute \
-H "Content-Type: application/json" \
-d '{"left":"...","right":"..."}'
Schema de intrare
| Câmp | Tip | Obligatoriu | Implicit |
|---|---|---|---|
left |
text | ✓ | – |
right |
text | ✓ | – |
Puncte de acces
GET https://cdrn.fr/api/v1/tools- listează toate instrumentele disponibileGET https://cdrn.fr/api/v1/tools/json-diff- obține schema acestui instrumentPOST https://cdrn.fr/api/v1/tools/json-diff/execute- execută acest instrument cu un payload JSON