Porovnat dvě JSON struktury

porovnává dvě JSON struktury a vypisuje přidání, odstranění a změny klíč po klíči

Proč porovnávat dvě JSON?

Porovnání dvou JSON struktur se pravidelně vrací v životě developera. API odpověď, která se mění po aktualizaci. Konfigurační soubor, který diverguje mezi dvěma prostředími. Export objektů, který se musí zarovnat na referenci. JSON diff přesně odpovídá na tuto otázku: co bylo přidáno, smazáno nebo modifikováno, a kde?

Řádkový diff (typu git diff) často nestačí. Pokud se formátování liší (mezery, pořadí klíčů), textový diff signalizuje stovky řádků, zatímco struktura dat je identická. JSON comparator pracuje na struktuře po parsing, což eliminuje tento šum a odhaluje pouze sémantické rozdíly.

Formát diffu produkovaného nástrojem

Pro každý rozdíl nástroj vrací:

  • cestu v zjednodušeném JSONPath formátu, například $.user.address[0].city;
  • typ mezi added (přidáno vpravo), removed (přítomno pouze vlevo), modified (různé hodnoty);
  • levou hodnotu a/nebo pravou hodnotu podle typu.

Prázdný diff znamená, že dva JSON jsou strukturálně identické, nezávisle na jejich formátování nebo pořadí klíčů.

Jak algoritmus prochází dvě struktury

Algoritmus je rekurzivní. Na každé úrovni identifikuje typ dvou porovnávaných hodnot:

  • Pokud jsou oba asociativní objekty, vezme sjednocení klíčů. Pro každý klíč sestoupí rekurzivně, nebo označí added/removed, pokud klíč existuje jen na jedné straně.
  • Pokud jsou oba uspořádaná pole, porovnává pozici po pozici. Rozdíl na začátku pole může posunout všechen zbytek, což produkuje ukecaný diff: je to přijatá limita naivního strukturálního diffu.
  • Pokud se typy liší (objekt proti poli, skalár proti null), je to označeno modified.
  • Pokud jsou dvě hodnoty skaláry (řetězec, číslo, boolean, null), stačí jednoduché striktní porovnání.

Pořadí klíčů v objektu nepočítá: {"a": 1, "b": 2} a {"b": 2, "a": 1} produkují prázdný diff. To je konformní s JSON sémantikou, kde pořadí není signifikantní. Naopak pořadí elementů pole počítá: pole je uspořádané konstrukcí.

Konkrétní příklad

Zde jsou dvě verze uživatelského objektu:

// levý
{
  "id": 42,
  "name": "Alice",
  "roles": ["admin", "editor"]
}

// pravý
{
  "id": 42,
  "name": "Alice Martin",
  "roles": ["admin", "viewer"],
  "active": true
}

Produkovaný diff:

  • $.name: modified, "Alice""Alice Martin"
  • $.roles[1]: modified, "editor""viewer"
  • $.active: added, true

Případy použití

  • Environment diff: porovnat výstup endpointu v pre-produkci a v produkci. Velmi užitečné při migraci nebo cache refresh.
  • Migration audit: porovnat export před a po transformaci pro ověření, že žádné pole nebylo ztraceno.
  • API regrese: před a po modifikaci porovnat odpověď pro identický požadavek. Prázdný diff potvrzuje non-regresi.
  • Konfigurační synchronizace: porovnat composer.json mezi dvěma větvemi, dva soubory .eslintrc, dvě Symfony konfigurace.
  • Snapshot testy: nahradit řádkové porovnání strukturálním porovnáním v integrační testovací sadě.

Limity strukturálního diffu

Porovnávání uspořádaných polí je známá limita naivních strukturálních diffů. Pokud vložíme element na začátek pole, všechny následující pozice jsou posunuty a diff signalizuje každý rozdíl jako modifikaci. Pro takové případy existují pokročilejší algoritmy (Myers, Patience, diff podle přirozeného klíče), ale vystupují z rámce obecného srovnávacího nástroje.

Diff také neříká, proč se změna udála: je to konstatování. Pro analýzu regrese je třeba zkřížit toto konstatování s commity, nasazeními a parametry požadavku.

JSON diff vs JSON Patch (RFC 6902)

Komplementární formát je JSON Patch (RFC 6902). Popisuje, ve formě operací (add, remove, replace, move, copy, test), jak transformovat JSON dokument na jiný. Tam, kde je náš diff konstatování (lidské), JSON Patch je recept (strojový). Obě reprezentace jsou ekvivalentní pro jednoduché případy, a JSON Patch je užitečný pro RESTful API, která přijímají částečné modifikace.

Často kladené otázky

Závisí diff na pořadí klíčů?

Ne: pro JSON objekt není pořadí signifikantní. Comparator produkuje stejný výsledek, ať jsou klíče setříděny nebo ne.

Jak spravovat pole, kde pořadí není důležité?

Nástroj ve výchozím nastavení považuje pole za uspořádaná (to je JSON sémantika). Pokud zpracováváte množiny, setřiďte obě pole podle přirozeného klíče před porovnáním, nebo použijte specializovanou srovnávací službu, která bere tuto sémantiku v úvahu.

Jaký je rozdíl s Git diffem?

Git porovnává řádky textu. Pokud se indentace nebo pořadí klíčů liší, Git diff je velmi ukecaný. JSON diff pracuje na parsované struktuře a signalizuje pouze datové rozdíly.

Je nevalidní JSON přijat?

Ne: pokud se jeden ze dvou JSON neparsuje, nástroj vrací chybu. Nejprve validujte naším JSON validátorem.

Ukázka požadavku

curl -X POST https://cdrn.fr/api/v1/tools/json-diff/execute \
  -H "Content-Type: application/json" \
  -d '{"left":"...","right":"..."}'

Vstupní schéma

Pole Typ Povinné Výchozí
left text
right text

Koncové body

  • GET https://cdrn.fr/api/v1/tools - vypíše všechny dostupné nástroje
  • GET https://cdrn.fr/api/v1/tools/json-diff - získá schéma tohoto nástroje
  • POST https://cdrn.fr/api/v1/tools/json-diff/execute - spustí tento nástroj s JSON payloadem