Dev Tools

Guía Completa de JSON Patch (RFC 6902): Operaciones, Ejemplos y Mejores Prácticas

Qué Es JSON Patch y Por Qué Es Importante

JSON Patch es un formato estandarizado, definido en la RFC 6902, que describe una secuencia de operaciones para modificar un documento JSON. En lugar de enviar un documento completo cada vez que necesitas actualizar un recurso, JSON Patch te permite describir únicamente los cambios específicos que deben aplicarse. Esto resulta especialmente valioso en arquitecturas de APIs REST donde la eficiencia en la transferencia de datos y la precisión de las actualizaciones son requisitos fundamentales.

El estándar fue publicado por la Internet Engineering Task Force (IETF) en abril de 2013 y se ha convertido en una pieza fundamental del ecosistema de APIs modernas. Se utiliza junto con el método HTTP PATCH (definido en la RFC 5789) y el tipo de contenido application/json-patch+json. Mientras que PUT reemplaza un recurso completo, PATCH con JSON Patch permite actualizaciones parciales, quirúrgicas y atómicas.

Nuestra herramienta de comparación JSON puede generar y visualizar parches JSON Patch, facilitando la comprensión de las diferencias entre dos documentos. En esta guía profundizaremos en cada aspecto del estándar: sus seis operaciones, el sistema de direccionamiento JSON Pointer, ejemplos prácticos, manejo de errores, comparación con JSON Merge Patch y mejores prácticas para integrarlo en tus APIs.

JSON Pointer (RFC 6901): El Sistema de Direccionamiento

Antes de entender las operaciones de JSON Patch, es imprescindible dominar JSON Pointer, definido en la RFC 6901. JSON Pointer es una sintaxis de cadena de texto que identifica una ubicación específica dentro de un documento JSON. Cada operación de JSON Patch utiliza un campo "path" que contiene un JSON Pointer para indicar exactamente dónde debe aplicarse el cambio.

Sintaxis de JSON Pointer

Un JSON Pointer es una cadena compuesta por segmentos separados por el carácter /. Cada segmento representa una clave de objeto o un índice de array. La cadena vacía "" apunta al documento raíz completo. Algunos ejemplos ilustrativos:

  • "" — apunta al documento raíz.
  • "/nombre" — apunta a la clave nombre en el objeto raíz.
  • "/usuario/direccion/ciudad" — apunta a la clave ciudad dentro del objeto direccion, que a su vez está dentro de usuario.
  • "/items/0" — apunta al primer elemento del array items.
  • "/items/-" — apunta al final del array items (se usa para agregar elementos al final).

Existen dos caracteres especiales que requieren escape en JSON Pointer: la barra / se representa como ~1 y la tilde ~ se representa como ~0. Por ejemplo, si una clave se llama datos/personales, el puntero sería /datos~1personales. Estas reglas de escape son esenciales para manejar correctamente claves con caracteres especiales en documentos JSON complejos.

Diferencia entre Índices de Array y Claves de Objeto

Es importante distinguir cómo JSON Pointer trata los arrays frente a los objetos. Para arrays, los segmentos numéricos representan índices basados en cero. El segmento especial - se refiere a la posición después del último elemento existente, lo cual es útil exclusivamente para la operación add. Para objetos, los segmentos son las claves literales del objeto, sin importar si parecen números. Si un objeto tiene la clave "0", el puntero /0 se refiere a esa clave de texto, no a un índice de array.

Las 6 Operaciones de JSON Patch

JSON Patch define exactamente seis operaciones. Cada operación es un objeto JSON que contiene al menos un campo "op" (el nombre de la operación) y un campo "path" (la ubicación objetivo). Algunas operaciones requieren campos adicionales como "value" o "from". Las operaciones se aplican secuencialmente en el orden en que aparecen en el array del parche.

1. add — Agregar un Valor

La operación add inserta un nuevo valor en la ubicación especificada por path. Su comportamiento varía según el contexto: si el destino es un miembro de un objeto, agrega la clave con el valor proporcionado (o reemplaza el valor existente si la clave ya existe). Si el destino es un índice de array, inserta el valor en esa posición desplazando los elementos existentes.

[
{ "op": "add", "path": "/email", "value": "[email protected]" },
{ "op": "add", "path": "/roles/-", "value": "editor" },
{ "op": "add", "path": "/direcciones/0", "value": { "tipo": "trabajo", "ciudad": "Madrid" } }
]

El primer ejemplo agrega o reemplaza la clave email en el objeto raíz. El segundo agrega "editor" al final del array roles usando el índice especial -. El tercero inserta un objeto completo al inicio del array direcciones.

2. remove — Eliminar un Valor

La operación remove elimina el valor en la ubicación indicada por path. Si la ruta apunta a un miembro de un objeto, elimina esa clave y su valor. Si apunta a un elemento de un array, elimina ese elemento y desplaza los elementos posteriores para cerrar el hueco. La operación falla si la ruta no existe en el documento.

[
{ "op": "remove", "path": "/temporal" },
{ "op": "remove", "path": "/items/2" }
]

Es fundamental tener en cuenta que al eliminar un elemento de un array, los índices de los elementos posteriores cambian. Por lo tanto, si necesitas eliminar múltiples elementos de un array, debes hacerlo en orden descendente de índices o recalcular los índices después de cada eliminación.

3. replace — Reemplazar un Valor

La operación replace sustituye el valor existente en la ubicación especificada por un nuevo valor. Es semánticamente equivalente a ejecutar un remove seguido de un add en la misma ubicación, pero se expresa como una única operación atómica. La ruta debe existir previamente; de lo contrario, la operación falla.

[
{ "op": "replace", "path": "/nombre", "value": "Ana María" },
{ "op": "replace", "path": "/configuracion/tema", "value": "oscuro" }
]

La operación replace es probablemente la más utilizada en la práctica, ya que la mayoría de las actualizaciones parciales de recursos implican modificar valores existentes en lugar de agregar o eliminar campos.

4. move — Mover un Valor

La operación move traslada un valor de una ubicación a otra dentro del documento. Utiliza un campo adicional "from" que indica la ubicación de origen. Es equivalente a un remove en from seguido de un add en path. La ubicación de destino no puede ser un descendiente de la ubicación de origen.

[
{ "op": "move", "from": "/nombre_temporal", "path": "/nombre_definitivo" },
{ "op": "move", "from": "/items/0", "path": "/items/2" }
]

La operación move es útil para reestructurar documentos, renombrar claves o reordenar elementos dentro de un array. Ten en cuenta que mover un elemento de un array modifica los índices de los demás elementos, lo cual puede afectar operaciones posteriores del mismo parche.

5. copy — Copiar un Valor

La operación copy duplica un valor desde una ubicación de origen a una ubicación de destino. Al igual que move, utiliza el campo "from". A diferencia de move, el valor original permanece intacto en su ubicación de origen. El valor copiado es una copia profunda, por lo que las modificaciones posteriores en la copia no afectan al original.

[
{ "op": "copy", "from": "/plantilla", "path": "/configuracion_actual" },
{ "op": "copy", "from": "/usuarios/0", "path": "/usuario_destacado" }
]

Esta operación resulta muy práctica cuando necesitas inicializar una nueva sección de un documento basándote en valores existentes, o cuando quieres crear respaldos dentro del mismo documento antes de realizar modificaciones.

6. test — Verificar un Valor

La operación test verifica que el valor en la ubicación especificada sea igual al valor proporcionado. No modifica el documento; su propósito es servir como precondición para las operaciones siguientes. Si la verificación falla, todo el parche se aborta y el documento permanece sin cambios. La comparación utiliza igualdad profunda según la especificación JSON.

[
{ "op": "test", "path": "/version", "value": 3 },
{ "op": "replace", "path": "/version", "value": 4 },
{ "op": "replace", "path": "/datos", "value": "nuevos datos" }
]

En este ejemplo, el parche primero verifica que la versión actual sea 3. Solo si esta verificación pasa, se actualizan la versión y los datos. Esto implementa un mecanismo de control de concurrencia optimista directamente en el parche, evitando conflictos cuando múltiples clientes intentan actualizar el mismo recurso simultáneamente.

Aplicar JSON Patch en APIs REST

La integración de JSON Patch en APIs REST sigue un patrón bien establecido. El cliente envía una solicitud HTTP PATCH al endpoint del recurso con el encabezado Content-Type: application/json-patch+json y un cuerpo que contiene el array de operaciones. El servidor valida las operaciones, las aplica al recurso y devuelve el recurso actualizado.

Ejemplo de Solicitud HTTP

Una solicitud típica de JSON Patch para actualizar un perfil de usuario tendría esta forma:

PATCH /api/v1/usuarios/42 HTTP/1.1
Content-Type: application/json-patch+json

[
{ "op": "test", "path": "/version", "value": 7 },
{ "op": "replace", "path": "/perfil/nombre", "value": "María García" },
{ "op": "add", "path": "/perfil/telefono", "value": "+34 612 345 678" },
{ "op": "remove", "path": "/perfil/fax" },
{ "op": "replace", "path": "/version", "value": 8 }
]

El servidor debe procesar las operaciones secuencialmente. Si alguna operación falla (por ejemplo, el test no se cumple porque otro cliente ya modificó el recurso), el servidor debe devolver un código de error 409 Conflict o 422 Unprocessable Entity y dejar el recurso intacto.

Ventajas sobre PUT en APIs REST

Usar JSON Patch con PATCH en lugar de PUT ofrece múltiples beneficios. Primero, reduce significativamente el tamaño del payload: en lugar de enviar un objeto completo de cientos de campos, envías solo las operaciones necesarias. Segundo, elimina el problema de sobrescritura accidental, donde un cliente con una copia desactualizada del recurso podría sobrescribir cambios realizados por otros clientes. Tercero, permite actualizaciones atómicas condicionales gracias a la operación test, implementando control de concurrencia optimista sin necesidad de encabezados ETag adicionales.

Además, JSON Patch proporciona un registro auditable de cambios. Cada parche aplicado describe exactamente qué se modificó, lo cual es invaluable para sistemas que requieren trazabilidad completa de cambios, como aplicaciones financieras o de cumplimiento normativo.

Manejo de Errores en JSON Patch

La RFC 6902 establece reglas claras sobre el manejo de errores. El principio fundamental es la atomicidad: si cualquier operación dentro de un parche falla, todo el parche debe revertirse y el documento debe quedar en su estado original. No existen aplicaciones parciales de un parche.

Errores Comunes y Sus Causas

Los errores más frecuentes al aplicar parches JSON incluyen:

  • Ruta inexistente: Las operaciones remove, replace, move y test fallan si la ruta especificada no existe en el documento actual. Solo add puede crear nuevas rutas, y únicamente el último segmento puede ser nuevo (todos los segmentos intermedios deben existir).
  • Índice fuera de rango: Acceder a un índice de array que excede la longitud del array produce un error. El índice especial - solo es válido para la operación add.
  • Fallo en test: Si el valor actual no coincide con el valor esperado en una operación test, todo el parche se aborta. Esto es por diseño: el test existe precisamente para prevenir la aplicación de cambios cuando las precondiciones no se cumplen.
  • Formato inválido: Operaciones con campos faltantes (como op o path) o con un nombre de operación no reconocido causan el rechazo del parche completo.
  • Movimiento circular: Intentar mover un nodo a una ubicación que es descendiente de sí mismo produce un error, ya que el resultado sería un documento inconsistente.

Códigos de Estado HTTP para Errores

En el contexto de APIs REST, los servidores deben utilizar códigos de estado apropiados para comunicar errores de parche. El código 400 Bad Request indica que el parche tiene un formato inválido o contiene operaciones malformadas. El código 409 Conflict se usa cuando una operación test falla, indicando un conflicto de concurrencia. El código 422 Unprocessable Entity se emplea cuando el parche está bien formado pero no se puede aplicar al estado actual del documento, por ejemplo, porque una ruta referenciada no existe. Al devolver estos códigos, el cuerpo de la respuesta debe incluir detalles sobre qué operación falló y por qué, para facilitar la depuración por parte del cliente.

JSON Patch vs. JSON Merge Patch (RFC 7396)

Es habitual confundir JSON Patch (RFC 6902) con JSON Merge Patch (RFC 7396). Aunque ambos están diseñados para modificar documentos JSON, sus enfoques y capacidades difieren significativamente. Comprender estas diferencias es crucial para elegir la herramienta adecuada en cada situación.

JSON Merge Patch: Simplicidad con Limitaciones

JSON Merge Patch utiliza un enfoque intuitivo: el cliente envía un documento JSON que representa los cambios deseados. Los campos presentes en el parche reemplazan los campos correspondientes del documento original. Los campos con valor null se eliminan del documento. Los campos no mencionados en el parche permanecen sin cambios. El tipo de contenido es application/merge-patch+json.

// Documento original
{ "nombre": "Ana", "edad": 28, "email": "[email protected]" }

// JSON Merge Patch
{ "edad": 29, "email": null, "telefono": "+34 612 345 678" }

// Resultado
{ "nombre": "Ana", "edad": 29, "telefono": "+34 612 345 678" }

Este enfoque es más simple e intuitivo, pero tiene limitaciones importantes que JSON Patch no tiene.

Cuándo Elegir Cada Formato

JSON Merge Patch no puede distinguir entre establecer un valor como null y eliminar un campo, ya que ambos se representan con null. Tampoco puede manipular arrays de forma granular: siempre reemplaza el array completo. No soporta operaciones de test para control de concurrencia ni operaciones de move o copy. En cambio, JSON Patch ofrece control total sobre cada aspecto del documento.

  • Usa JSON Merge Patch cuando las actualizaciones son simples (cambiar campos de nivel superior), no necesitas manipular arrays individualmente, tu esquema nunca usa null como valor legítimo y no necesitas control de concurrencia a nivel de parche.
  • Usa JSON Patch cuando necesitas manipulación precisa de arrays, operaciones condicionales con test, mover o copiar valores dentro del documento, preservar null como valor válido o construir secuencias complejas de cambios atómicos.

En la práctica, muchas APIs soportan ambos formatos y dejan que el cliente elija el más apropiado para cada caso de uso, diferenciándolos mediante el encabezado Content-Type.

Ejemplos Prácticos y Patrones Avanzados

Más allá de las operaciones individuales, JSON Patch permite patrones sofisticados combinando múltiples operaciones en un solo parche atómico. Estos patrones son comunes en aplicaciones del mundo real y demuestran la flexibilidad del estándar.

Actualización Condicional con Versionado

Uno de los patrones más útiles es combinar test con operaciones de modificación para implementar actualización optimista. El cliente lee el recurso, realiza cambios localmente y luego envía un parche que incluye un test para verificar que el recurso no ha cambiado desde la última lectura.

[
{ "op": "test", "path": "/metadata/updatedAt", "value": "2026-03-17T10:30:00Z" },
{ "op": "replace", "path": "/metadata/updatedAt", "value": "2026-03-18T14:15:00Z" },
{ "op": "replace", "path": "/estado", "value": "procesado" },
{ "op": "add", "path": "/historial/-", "value": { "accion": "procesado", "fecha": "2026-03-18T14:15:00Z" } }
]

Si otro cliente modificó el recurso entre la lectura y la escritura, el test fallará y el parche se rechazará, evitando la pérdida de datos por sobrescritura ciega.

Reestructuración de Documentos

Puedes usar move y copy para reorganizar la estructura de un documento sin perder datos. Por ejemplo, para migrar un esquema que cambió la ubicación de ciertos campos:

[
{ "op": "move", "from": "/config/database/host", "path": "/config/connections/primary/host" },
{ "op": "move", "from": "/config/database/port", "path": "/config/connections/primary/port" },
{ "op": "copy", "from": "/config/connections/primary", "path": "/config/connections/replica" },
{ "op": "replace", "path": "/config/connections/replica/host", "value": "replica.ejemplo.com" },
{ "op": "remove", "path": "/config/database" }
]

Este parche atómico migra la configuración de base de datos a una nueva estructura con conexiones primaria y réplica, todo en una sola operación transaccional.

Manipulación Precisa de Arrays

A diferencia de JSON Merge Patch, JSON Patch permite insertar, eliminar, mover y reemplazar elementos individuales dentro de arrays sin afectar los demás elementos:

[
{ "op": "add", "path": "/permisos/1", "value": "escribir" },
{ "op": "remove", "path": "/permisos/3" },
{ "op": "replace", "path": "/permisos/0", "value": "leer-todo" },
{ "op": "move", "from": "/permisos/2", "path": "/permisos/0" }
]

Al trabajar con arrays, recuerda que las operaciones se aplican secuencialmente y que los índices pueden cambiar después de cada inserción o eliminación. Planifica cuidadosamente el orden de las operaciones para evitar errores de índice.

Implementaciones y Bibliotecas Populares

El ecosistema de JSON Patch cuenta con implementaciones robustas en prácticamente todos los lenguajes de programación. En JavaScript, la biblioteca fast-json-patch es la más utilizada, ofreciendo funciones para aplicar parches, generar parches a partir de la comparación de dos documentos y validar parches antes de aplicarlos. En Python, jsonpatch proporciona una API similar con soporte para la generación automática de parches. En Java, la especificación JSR 374 (JSON Processing) incluye soporte nativo para JSON Patch a través de javax.json.JsonPatch.

Al elegir una biblioteca, verifica que cumpla completamente con la RFC 6902, que soporte la atomicidad (revertir cambios si una operación falla) y que incluya validación de parches previa a la aplicación. Muchas bibliotecas también soportan la generación de parches mediante la comparación de dos documentos, lo cual es extremadamente útil para crear parches automáticamente a partir de diferencias detectadas.

Mejores Prácticas para Usar JSON Patch

Para integrar JSON Patch de manera efectiva en tus aplicaciones y APIs, considera las siguientes recomendaciones basadas en la experiencia de la industria:

  • Siempre incluye operaciones test: Antes de modificar valores críticos, agrega un test para verificar el estado esperado. Esto previene condiciones de carrera y conflictos de concurrencia.
  • Valida parches antes de aplicarlos: Verifica que el parche tenga un formato válido, que las rutas sean sintácticamente correctas y que las operaciones contengan todos los campos requeridos antes de intentar aplicarlo al documento.
  • Ordena las operaciones cuidadosamente: Dado que las operaciones se aplican secuencialmente, el orden importa. Realiza las verificaciones (test) primero, luego las eliminaciones (en orden descendente de índice para arrays) y finalmente las adiciones y reemplazos.
  • Limita el tamaño de los parches: Un parche con cientos de operaciones es difícil de depurar y propenso a errores. Si necesitas cambios masivos, considera usar PUT para reemplazar el recurso completo.
  • Registra los parches aplicados: Almacena un historial de parches aplicados a cada recurso. Esto proporciona trazabilidad completa de cambios y permite implementar funcionalidades de deshacer.
  • Documenta las restricciones: No todos los campos de un recurso deberían ser modificables mediante parches. Documenta claramente qué rutas son inmutables y valida esta restricción en el servidor.
  • Usa nuestra herramienta para depuración: Nuestra herramienta de comparación JSON permite visualizar las diferencias entre documentos y entender los parches generados, todo directamente en tu navegador sin enviar datos a ningún servidor.

JSON Patch es un estándar maduro y bien definido que resuelve problemas reales en el desarrollo de APIs modernas. Dominar sus operaciones, comprender el sistema de direccionamiento JSON Pointer y seguir las mejores prácticas de manejo de errores te permitirá construir APIs más eficientes, robustas y seguras. La combinación de actualizaciones parciales, atomicidad y control de concurrencia optimista hace de JSON Patch una herramienta indispensable en el arsenal de cualquier desarrollador de APIs.

← Volver al Blog