
JSONPath en el navegador: Una referencia práctica y un tester para los patrones que realmente usas
📷 Pixabay / PexelsJSONPath en el navegador: Una referencia práctica y un tester para los patrones que realmente usas
Deja de adivinar si tu consulta JSONPath coincidirá con lo que esperas. Una guía práctica de filtros, slices y el operador de descenso recursivo — con un tester gratuito.
He trabajado con APIs el tiempo suficiente para recordar cuando XML era el predeterminado y XPath era el lenguaje de consulta que todos aprendían. JSONPath es el equivalente JSON, y después de años de evitarlo (porque podía simplemente escribir JavaScript, ¿verdad?), me he convertido. Hay demasiados lugares donde JSONPath es el único lenguaje disponible — variables de Postman, AWS Step Functions, selectores de Kubernetes, filtros de Datadog — y ser fluido ahorra tiempo real.
Esta guía es la referencia que desearía haber tenido cuando empecé. Cubriremos la sintaxis que realmente aparece en producción, los errores que me costaron horas, y cómo el JSONPath Tester en ToolBox Hubs te permite verificar tus expresiones antes de pegarlas en cualquier lugar consecuente.
Qué es JSONPath, rápidamente
JSONPath es un lenguaje de consulta para documentos JSON. Le das una expresión como $.store.book[*].author y devuelve todos los valores que coinciden. El $ es la raíz, los puntos y corchetes navegan en la estructura, y los operadores especiales permiten filtrar, slicing y atravesar recursivamente.
Si has usado XPath para XML, el modelo mental se transfiere directamente. Si no, piensa en él como una versión más potente de la notación de punto en JavaScript — una que puede expresar "todos los libros con precio bajo $10" o "cada autor a cualquier profundidad en el documento" en una sola línea.
El ejemplo canónico que todos usan viene del artículo original de Stefan Goessner:
{
"store": {
"book": [
{ "category": "fiction", "author": "Tolkien", "price": 22.99 },
{ "category": "reference", "author": "Rees", "price": 8.95 }
],
"bicycle": { "color": "red", "price": 19.95 }
}
}
$.store.book[*].author devuelve ["Tolkien", "Rees"]. $..price devuelve [22.99, 8.95, 19.95]. $.store.book[?(@.price < 10)] devuelve el segundo objeto book. Eso es todo el juego.
Los operadores que usarás el 90% del tiempo
Hay docenas de operadores JSONPath. Cinco de ellos cubren casi todo lo que escribirás en la práctica.
$ — La raíz
Cada expresión JSONPath comienza con $. Se refiere al tope del documento. Técnicamente puedes omitirlo (algunas bibliotecas son indulgentes) pero escribirlo explícitamente hace clara la intención.
.field — Acceso a hijo
Notación de punto estándar. $.users.0.email camina desde la raíz al array users, elige el índice 0 y lee email. Igual que JavaScript excepto que el 0 funciona como nombre de propiedad.
[n] — Índice de array
Notación de corchetes para acceso a array, útil cuando los índices son dinámicos o cuando el nombre del campo tiene caracteres especiales. $.users[0], $.users[-1] (último elemento), $.users[0:3] (slice de 0 a 3 exclusivo).
Los índices negativos cuentan desde el final. $.users[-1] es el último usuario. $.users[-3:] da los últimos tres. Esto no se soporta en todas las implementaciones — RFC 9535 lo estandariza, pero verifica tu biblioteca si dependes de ello.
[*] — Wildcard
Coincide con todos los elementos en un array o todos los valores en un objeto. $.users[*].email devuelve el email de cada usuario. $.config.* devuelve cada valor en el objeto config. Combinado con acceso a propiedad, así es como aplanas estructuras comunes.
..field — Descenso recursivo
El operador más potente y el que más uso. $..price encuentra cada campo price en cualquier parte del documento, sin importar cuán profundamente anidado. Útil cuando no conoces o no te importa la estructura exacta.
El descenso no se preocupa por el path — simplemente encuentra todo lo que coincide con el patrón. Eso lo hace genial para exploración de datos ad hoc ("¿esta respuesta contiene algún ID de usuario?") y peligroso si tus datos tienen el mismo nombre de clave en diferentes contextos (un campo name en usuarios y un campo name en roles ambos coincidirán con $..name).
Filtros: Donde la gente se atasca
Las expresiones de filtro se escriben [?(...)] donde el contenido es una expresión booleana evaluada contra cada elemento en un array. Dentro del filtro, @ se refiere al elemento actual.
$.store.book[?(@.price < 10)]
$.users[?(@.role == 'admin')]
$.events[?(@.timestamp > 1700000000)]
El @ es la parte que confunde a la gente. Es el equivalente a this o el elemento actual en un forEach. Sin él, el filtro no puede referenciar ningún campo — [?(price < 10)] no funciona porque price no está definido; el motor no sabe que debe mirar dentro del elemento actual.
Operadores de comparación
Universales en todas las bibliotecas: ==, !=, <, >, <=, >=.
El lado derecho puede ser un literal: un número (@.age > 18), una cadena entre comillas simples (@.role == 'admin'), una cadena entre comillas dobles, true, false, o null.
Lo que NO es universal: comparar dos campos entre sí (@.price > @.cost), coincidencia regex (@.email =~ /.*@example\.com/), llamadas a funciones como length() o match(). Algunas bibliotecas las soportan; muchas no. El JSONPath Tester en ToolBox Hubs soporta las comparaciones básicas contra valores literales, lo que cubre la gran mayoría de consultas reales.
Combinaciones booleanas
Las implementaciones estándar soportan && y || para combinar condiciones:
$.products[?(@.in_stock == true && @.price < 50)]
$.events[?(@.severity == 'error' || @.severity == 'critical')]
Si te encuentras escribiendo lógica booleana compleja en JSONPath, eso suele ser una señal de bajar a código real — tu yo futuro leyendo la expresión en seis meses te lo agradecerá. JSONPath brilla para selecciones simples; la lógica de negocio compleja pertenece a un lenguaje real.
Slices: Para cuando solo necesitas algunos elementos
[start:end:step] funciona exactamente como el slicing de Python.
[0:5]— primeros 5 elementos[5:]— desde el índice 5 en adelante[:3]— primeros 3 elementos (igual que[0:3])[-3:]— últimos 3 elementos[::2]— cada otro elemento[::-1]— invertido (no soportado en todas partes)
El slicing es una de las partes más limpias de JSONPath. Es un puerto directo de Python y se comporta predeciblemente. Lo uso mucho para patrones de "dame los primeros N resultados" o "dame todo excepto el primero".
Patrones que realmente aparecen en el trabajo
La teoría está bien; veamos las consultas reales.
Filtrar respuestas de API
Tu API devuelve resultados paginados y quieres encontrar elementos específicos. JSONPath en tu framework de pruebas o Postman:
$.data[?(@.status == 'active')].id
Devuelve los IDs de todos los elementos activos. Si la API no tiene un parámetro "filter by status", esto es más rápido que transformar en código.
Extraer valores de payloads de webhook
Estás procesando webhooks de Stripe, GitHub o similares, y necesitas tomar campos específicos. JSONPath en reglas de AWS EventBridge, Step Functions o Logic Apps:
$.detail.payload.items[*].sku
Devuelve el SKU de cada elemento en una orden. Las herramientas de flujo cloud dependen de JSONPath porque es declarativo e inspeccionable, donde JavaScript embebido sería una carga de seguridad y mantenibilidad.
Encontrar elementos en datos profundamente anidados
No conoces la estructura exacta pero sabes que hay un ID de usuario en alguna parte:
$..userId
Devuelve cada campo userId en el documento, independientemente de la profundidad de anidamiento. Útil para exploración cuando trabajas con respuestas de API desconocidas o integraciones de terceros.
Validar restricciones tipo schema
Necesitas verificar que todos los elementos en una lista tienen un campo específico:
$.users[?(!@.email)]
Devuelve usuarios sin email. Si el resultado está vacío, tus datos están limpios. Este patrón funciona bien en scripts de prueba CI donde parseas una salida JSON y haces aserciones sobre su estructura.
Los problemas (una lista personal)
Estas son las cosas que me han costado horas.
El @ en filtros es obligatorio. Escribir [?(price < 10)] en lugar de [?(@.price < 10)] es el error más común. Sin @, el motor no sabe que price se refiere a un campo en el elemento actual.
Los filtros devuelven elementos coincidentes, no el campo por el que filtraste. $..book[?(@.price < 10)] devuelve objetos book, no precios. Para obtener solo los precios: $..book[?(@.price < 10)].price.
Las comillas importan dentro de las expresiones. Usa comillas simples dentro de cadenas JSONPath para evitar confundir el lenguaje circundante. En un archivo de configuración JSON tu JSONPath es un valor de cadena, así que el JSONPath en sí usa comillas simples: "$.users[?(@.role == 'admin')]". Mezclarlas crea errores de parseo.
El descenso recursivo encuentra coincidencias sombra. $..name coincidirá con cada campo name, incluyendo los de objetos anidados no relacionados. Si tienes campos name de usuario y campos name de producto en el mismo documento, esto devolverá ambos. Sé específico cuando importe.
Índice 0 vs. propiedad '0'. $.items[0] funciona en arrays. $.items.0 puede o no funcionar — la mayoría de parsers lo rechazan para arrays (es solo de corchetes) pero lo aceptan como nombre de propiedad en objetos. Quédate con corchetes para acceso a array.
Los resultados vacíos no son errores. Si tu JSONPath no coincide con nada, obtienes un array vacío [], no una excepción. Este es el comportamiento correcto, pero puede ocultar errores tipográficos. Si esperabas resultados y no obtuviste ninguno, verifica el path.
RFC 9535 vs. bibliotecas era Goessner
El artículo original de 2007 que definió JSONPath era informal — describía sintaxis con ejemplos pero no especificaba formalmente el comportamiento en casos límite. Diferentes implementaciones de bibliotecas tomaron diferentes decisiones, y a lo largo de los años las diferencias se acumularon.
En 2024, RFC 9535 fue publicado como la especificación oficial. Estandariza sintaxis y semántica, particularmente alrededor de:
- Gramática de expresiones de filtro
- Extensiones de función (
length,count,match,search,value) - Paths normalizados en la salida (cada resultado incluye su ubicación)
- Perfil I-Regexp para coincidencia regex
Si estás iniciando un nuevo proyecto, prefiere bibliotecas que apunten a RFC 9535 — jsonpath-rfc9535 para Node, ports Python jsonpath-rfc9535, herramienta CLI jp. Si mantienes código existente, probablemente estés en una implementación de era Goessner; eso está bien, simplemente sé consciente de que las diferencias existen.
El JSONPath Tester en ToolBox Hubs implementa los operadores más comunes que funcionan consistentemente entre implementaciones. Es intencionadamente conservador en sintaxis de filtro para evitar probar cosas que no funcionarán en tu entorno objetivo.
Donde JSONPath pierde frente a jq
Te estaría engañando si no mencionara jq.
JSONPath es bueno para encontrar valores en JSON. jq es bueno para encontrar Y transformar JSON. Si necesitas:
- Proyectar objetos a una forma diferente (
.users | map({id, email})) - Agregar valores (
map(.price) | add) - Componer múltiples operaciones
- Manejar lógica condicional compleja
jq es dramáticamente mejor. JSONPath no tiene agregación, no tiene map/reduce y no tiene composición de funciones. No son bugs — son decisiones de alcance. JSONPath es un lenguaje de consulta. jq es un lenguaje de transformación.
La herramienta correcta depende de tu entorno. JSONPath está en todas partes porque es simple de embeber (sin dependencias, solo un parser de cadena). jq requiere un binario y es más difícil de usar en contextos de navegador o entornos restringidos. En una prueba de Postman o un mapeo de entrada de Step Function, solo tienes JSONPath. En un pipeline de shell o una transformación de datos del lado del servidor, jq suele ser mejor.
Un flujo de trabajo práctico
Así es como realmente uso JSONPath ahora:
-
Abro la respuesta de API o el documento JSON en el JSON Formatter para hacerlo legible.
-
Identifico el valor o valores que quiero extraer. Normalmente puedo trazar el path mentalmente: "array users, elemento N, campo role, igual a admin."
-
Abro el JSONPath Tester, pego el JSON y escribo la expresión. Itero hasta que devuelva exactamente lo que quiero.
-
Copio la expresión que funciona donde tenga que vivir — prueba de Postman, AWS Step Function, selector de Kubernetes.
-
Si estoy construyendo algo más complejo (transformación, agregación), cambio a jq.
Este flujo de trabajo elimina horas de depuración "por qué no coincide mi JSONPath" de las integraciones. El tester es el paso faltante que la mayoría de tutoriales se saltan — muestran la sintaxis y asumen que puedes escribirla correctamente al primer intento. Generalmente no puedes, especialmente con filtros.
Recomendaciones de herramientas para el flujo JSON más amplio
JSONPath es una herramienta en un flujo JSON. Emparejarla con utilidades relacionadas hace que toda la pipeline sea más fluida:
- JSON Formatter — formatea bonito antes de consultar; el JSON minificado es ilegible
- JSON Diff — cuando JSONPath devuelve resultados diferentes entre dos respuestas, dífalas para ver qué cambió
- JSON to TypeScript — genera tipos TypeScript desde una muestra, luego usa el tipo para escribir JSONPath que coincida con el schema
- JSON Schema Generator — produce un JSON Schema para validación; complementario a JSONPath que es para consulta
El JSONPath Tester es gratis, solo de navegador y nunca envía tu JSON a ninguna parte. Pega, consulta, itera, copia. Ese es el bucle.
Notas finales
JSONPath no es glamuroso. No es el lenguaje que alguien se emociona por aprender. Pero pasar una hora para volverte fluido se paga a través de años de depuración de API, configuración de flujos cloud y exploración de datos. La sintaxis es lo suficientemente pequeña para memorizar los patrones comunes. Los problemas son lo suficientemente predecibles para internalizar.
Si eres nuevo en él: empieza con los patrones básicos ($.field, $..field, $.array[*], [?(@.field == 'value')]) y evita la complejidad de filtros hasta que hayas usado lo simple por un tiempo. La mayoría de consultas del mundo real son simples. La complejidad viene de casos límite que generalmente se resuelven mejor con código.