Comparar dos estructuras JSON
- Panel
- Documentación
- API
¿Por qué comparar dos JSON?
Comparar dos estructuras JSON aparece con regularidad en la vida de un desarrollador. Una respuesta de API que cambia tras una actualización. Un fichero de configuración que diverge entre dos entornos. Una exportación de objetos que debe alinearse con una referencia. Un diff JSON responde precisamente a esa pregunta: ¿qué se ha añadido, suprimido o modificado, y en qué punto?
Un diff línea a línea (a la git diff) a menudo no basta. Si el formateo
difiere (espacios, orden de las claves), el diff textual señala cientos de líneas mientras la estructura
de datos es idéntica. Un comparador JSON trabaja sobre la estructura una vez parseada, lo que elimina ese
ruido y revela únicamente las desviaciones semánticas.
El formato del diff producido por la herramienta
Para cada desviación, la herramienta devuelve:
- una ruta en formato JSONPath simplificado, por ejemplo
$.user.address[0].city; - un tipo entre added (añadido a la derecha), removed (presente a la izquierda solamente), modified (valores distintos);
- el valor de la izquierda y/o el valor de la derecha según el tipo.
Un diff vacío significa que los dos JSON son estructuralmente idénticos, independientemente de su formateo o del orden de las claves.
Cómo recorre el algoritmo las dos estructuras
El algoritmo es recursivo. En cada nivel, identifica el tipo de los dos valores comparados:
- Si los dos son objetos asociativos, toma la unión de las claves. Para cada clave, desciende recursivamente, o marca added/removed si la clave solo existe en un lado.
- Si los dos son tablas ordenadas, compara posición por posición. Una diferencia al principio de la tabla puede desplazar todo el resto, lo que produce un diff verboso: es un límite asumido del diff estructural ingenuo.
- Si los tipos difieren (objeto frente a tabla, escalar frente a null), se marca modified.
- Si los dos valores son escalares (cadena, número, booleano, null), una simple comparación estricta basta.
El orden de las claves en un objeto no cuenta: {"a": 1, "b": 2} y {"b": 2, "a": 1}
producen un diff vacío. Esto se ajusta a la semántica JSON, donde el orden no es significativo. En
cambio, el orden de los elementos de una tabla sí cuenta: una tabla está ordenada por construcción.
Un ejemplo concreto
Estas son dos versiones de un objeto de usuario:
// gauche
{
"id": 42,
"name": "Alice",
"roles": ["admin", "editor"]
}
// droite
{
"id": 42,
"name": "Alice Martin",
"roles": ["admin", "viewer"],
"active": true
}
El diff produce:
$.name: modified,"Alice"→"Alice Martin"$.roles[1]: modified,"editor"→"viewer"$.active: added,true
Casos de uso
- Diff de entornos: comparar la salida de un endpoint en preproducción y en producción. Muy útil durante una migración o una actualización de caché.
- Auditoría de migración: comparar una exportación antes y después de la transformación para comprobar que no se ha perdido ningún campo.
- Regresión de API: antes y después de una modificación, comparar la respuesta para una misma petición. Un diff vacío confirma la ausencia de regresión.
- Sincronización de configuraciones: comparar
composer.jsonentre dos ramas, dos ficheros.eslintrc, dos configuraciones de Symfony. - Snapshot tests: sustituir una comparación línea a línea por una comparación estructural en una suite de tests de integración.
Límites del diff estructural
Comparar tablas ordenadas es un límite conocido de los diffs estructurales ingenuos. Si se inserta un elemento al principio de la tabla, todas las posiciones siguientes se desplazan y el diff señala cada desviación como una modificación. Para esos casos, existen algoritmos más avanzados (Myers, Patience, diff por clave natural), pero quedan fuera del alcance de una herramienta de comparación generalista.
El diff tampoco dice por qué ha ocurrido un cambio: es una constatación. Para analizar una regresión, hay que cruzar esa constatación con los commits, los despliegues y los parámetros de la petición.
JSON diff vs JSON Patch (RFC 6902)
Un formato complementario es JSON Patch (RFC 6902). Describe, en forma de operaciones
(add, remove, replace, move, copy,
test), cómo transformar un documento JSON en otro. Allí donde nuestro diff es una constatación
(humana), JSON Patch es una receta (máquina). Las dos representaciones son equivalentes para
los casos sencillos, y JSON Patch resulta útil para API RESTful que aceptan modificaciones
parciales.
Preguntas frecuentes
¿El diff depende del orden de las claves?
No: para un objeto JSON, el orden no es significativo. El comparador produce el mismo resultado tanto si las claves están ordenadas como si no.
¿Cómo gestionar las tablas cuyo orden no es importante?
La herramienta considera por defecto las tablas como ordenadas (es la semántica JSON). Si trata conjuntos, ordene las dos tablas por una clave natural antes de comparar, o utilice un servicio de comparación especializado que tenga en cuenta esa semántica.
¿Cuál es la diferencia con un diff Git?
Git compara líneas de texto. Si la indentación o el orden de las claves difiere, el diff Git es muy verboso. El diff JSON trabaja sobre la estructura parseada y solo señala las desviaciones de datos.
¿Se acepta un JSON no válido?
No: si alguno de los dos JSON no parsea, la herramienta devuelve un error. Valide primero con nuestro validador JSON.
Ejemplo de solicitud
curl -X POST https://cdrn.fr/api/v1/tools/json-diff/execute \
-H "Content-Type: application/json" \
-d '{"left":"...","right":"..."}'
Esquema de entrada
| Campo | Tipo | Obligatorio | Por defecto |
|---|---|---|---|
left |
text | ✓ | – |
right |
text | ✓ | – |
Puntos de acceso
GET https://cdrn.fr/api/v1/tools- lista todas las herramientas disponiblesGET https://cdrn.fr/api/v1/tools/json-diff- recupera el esquema de esta herramientaPOST https://cdrn.fr/api/v1/tools/json-diff/execute- ejecuta esta herramienta con un payload JSON