Comparar objetos JSON: claves añadidas, eliminadas y cambiadas
Una comparación de texto puede convertir una pequeña actualización de JSON en mucho ruido: la sangría, el orden de las claves y el formato ocultan los cambios reales.
Ejecutar — gratis
Corre en su navegador. Gratis y sin límite: sus datos no salen de esta página.
Esta herramienta compara valores ya interpretados. Separa las claves añadidas, eliminadas y cambiadas, recorre objetos anidados compartidos y asigna a cada resultado una ruta JSON Pointer inequívoca. Los arrays conservan su orden y se comparan completos. La operación es determinista, no usa la red y rechaza arrays, valores primitivos o null como entradas de nivel superior.
Cómo leer una diferencia estructural de JSON
El resultado divide las diferencias en colecciones de elementos añadidos, eliminados y cambiados. Una entrada añadida solo existe en el objeto nuevo; una eliminada solo aparece en el original; y una cambiada incluye los valores anterior y posterior. Cada elemento utiliza una ruta JSON Pointer que empieza por una barra. Por ejemplo, /profile/name señala la propiedad name dentro de profile. Este formato escapa una barra de una clave como ~1 y una virgulilla como ~0, por lo que no confunde claves literales con niveles anidados. El recorrido ordena las propiedades y produce resultados estables. El bloque counts resume cada categoría y el total. Si las tres listas están vacías, los objetos son estructuralmente iguales aunque el texto original tuviera otra sangría u otro orden de claves.
Tratamiento de objetos anidados y arrays
Cuando una misma clave contiene un objeto en ambos lados, la comparación desciende hasta la propiedad concreta que difiere. Si profile existe en las dos entradas y solo cambia profile.active, la ruta será /profile/active. Si una clave completa solo existe en un lado, se registra una sola vez con todo su valor; no se genera una entrada por cada descendiente. Los arrays se consideran valores JSON ordenados y completos: insertar, borrar, reordenar o modificar un elemento marca la propiedad del array como cambiada. Los primitivos y null se comparan directamente. Si cambia el tipo de una propiedad, también se informa como cambio. Únicamente las entradas superiores tienen una regla más estricta: before y after deben ser objetos JSON no nulos.
Uso de la comparación en revisiones y automatización
Envíe el objeto original en before y el propuesto en after. La herramienta del navegador funciona localmente, mientras que una solicitud de API cuesta $0.002 y devuelve la misma estructura determinista. Puede bloquear una publicación si desaparece una configuración protegida, comprobar que solo cambien rutas autorizadas o guardar una diferencia compacta para auditoría. Como el formato y el orden de claves no producen falsos positivos, resulta útil para configuraciones, webhooks, indicadores de funciones, permisos y respuestas normalizadas. Procese las rutas como JSON Pointer y considere también la categoría del cambio. Para arrays recibirá los valores completos y podrá aplicar después reglas específicas del dominio. Una entrada superior inválida devuelve un error claro, no una diferencia vacía engañosa.
Qué puede hacer con ella
Revisar publicaciones de configuración
Compare la configuración desplegada con la candidata y muestre solo cambios estructurales, sin ruido de espacios ni de orden.
Auditar la evolución de webhooks
Registre qué campos anidados aparecen, desaparecen o cambian entre dos ejemplos normalizados de un webhook.
Proteger ajustes autorizados
Compruebe las rutas en CI y detenga la publicación si se elimina o altera una opción protegida.
Preguntas frecuentes
¿Qué formato de ruta utiliza el resultado?
Cada ruta es un JSON Pointer al estilo RFC 6901. Las barras de las claves se codifican como ~1 y las virgulillas como ~0.
¿El orden de las claves cuenta como cambio?
No. Los objetos se comparan por claves y valores; un orden de serialización diferente no genera diferencias.
¿Cómo se comparan los arrays?
Son valores ordenados y se comparan completos. Cualquier edición, inserción, eliminación o reordenación marca el array como cambiado.
¿Puedo comparar dos arrays de nivel superior?
No. before y after deben ser objetos JSON no nulos; un array o valor primitivo superior causa un error de entrada.
¿Cuánto cuesta una solicitud de API?
La herramienta web se ejecuta localmente sin coste. Cada solicitud de API usa el precio base publicado de $0.002.
Para desarrolladores — acceso por API
Todo lo de esta página está disponible por programación. Esta sección es para equipos que quieren integrarlo en sus sistemas; el resto puede usar la herramienta de arriba sin más.
Endpoint de API
¿Prefiere automatizarlo? Un POST autenticado crea la tarea; el resultado llega por webhook o enlace firmado. La misma capacidad también se ejecuta aquí en la web, por email y desde Telegram — y pronto también desde nuestra app.
Llámela desde su stack
curl -X POST https://api.kit.forhosting.com/data/diff-json-objects \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"before":{"name":"Ada","profile":{"active":true,"score":8},"roles":["reader"]},"after":{"name":"Ada","profile":{"active":false,"score":8,"city":"London"},"roles":["reader","editor"]}}'const res = await fetch("https://api.kit.forhosting.com/data/diff-json-objects", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"before": {
"name": "Ada",
"profile": {
"active": true,
"score": 8
},
"roles": [
"reader"
]
},
"after": {
"name": "Ada",
"profile": {
"active": false,
"score": 8,
"city": "London"
},
"roles": [
"reader",
"editor"
]
}
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/data/diff-json-objects",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"before": {
"name": "Ada",
"profile": {
"active": true,
"score": 8
},
"roles": [
"reader"
]
},
"after": {
"name": "Ada",
"profile": {
"active": false,
"score": 8,
"city": "London"
},
"roles": [
"reader",
"editor"
]
}
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/data/diff-json-objects", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"before":{"name":"Ada","profile":{"active":true,"score":8},"roles":["reader"]},"after":{"name":"Ada","profile":{"active":false,"score":8,"city":"London"},"roles":["reader","editor"]}}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"before":{"name":"Ada","profile":{"active":true,"score":8},"roles":["reader"]},"after":{"name":"Ada","profile":{"active":false,"score":8,"city":"London"},"roles":["reader","editor"]}}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/data/diff-json-objects", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Ejemplo de solicitud
{
"before": {
"name": "Ada",
"profile": {
"active": true,
"score": 8
},
"roles": [
"reader"
]
},
"after": {
"name": "Ada",
"profile": {
"active": false,
"score": 8,
"city": "London"
},
"roles": [
"reader",
"editor"
]
}
}Ejemplo de respuesta
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "data.diff_json_objects",
"status": "queued",
"_links": {
"result": "/tasks/tsk_…/result"
}
}La API es asíncrona: la llamada devuelve un task_id al instante y el resultado llega por webhook. El polling está limitado a 1 req/s por tarea.
Precio
Precio publicado — sin tokens ni créditos inventados. Una tarea fallida no se cobra.
Límites
max_mb | 25 |
Errores
| HTTP | Código | Significado |
|---|---|---|
401 | unauthorized | API key ausente o inválida. |
402 | insufficient_balance | El saldo no cubre el precio de la tarea. |
404 | unknown_type | El tipo de tarea no existe. |
429 | rate_limited | Demasiadas peticiones. Use el webhook en vez de sondear. |