Tanto o ponteiro JSON quanto o JSONPath abordam localizacoes dentro de um documento JSON, e
ambos aparecem nos mesmos tipos de ferramentas: $ref no JSON Schema, operacoes
PATCH, diferencas baseadas em caminhos. Eles resolvem problemas diferentes, e saber qual
deles uma tarefa determinada realmente precisa evita escolher a ferramenta errada.
Ponteiro JSON: uma localizacao, RFC 6901
Um ponteiro e uma sequencia de tokens separados por /: /user/name significa a
chave name dentro do objeto user, /items/0 significa o primeiro elemento do
array items. Dois caracteres precisam ser escapados dentro de um token (~1 para um
/ literal, ~0 para um ~ literal), e a string vazia como ponteiro
significa o documento inteiro. Essa e toda a gramatica. Um ponteiro resolve para
exatamente um valor, ou falha, sem nada no meio: nao ha curinga, nao ha filtro, nao ha
forma de corresponder a mais de uma localizacao que ele nomeia.
{ "user": { "name": "Ada", "roles": ["admin", "editor"] } }
/user/name resolve para "Ada". /user/roles/1 resolve para "editor".
/user/email falha, porque essa chave nao existe. Nada na
sintaxe do ponteiro pode pedir “todas as funcoes” em uma unica expressao; o chamador
ja precisa conhecer o indice.
JSONPath: uma linguagem de consultas
JSONPath, padronizado como RFC 9535, foi feito para corresponder, nao apenas
enderecar. $.user.roles[*] retorna ambas as funcoes no exemplo acima em
uma unica consulta. $..email pesquisa em cada nivel do documento qualquer chave
chamada email, independentemente de quao profunda esteja aninhada. Expressoes de filtro como
$.items[?(@.price > 100)] selecionam elementos do array por uma condicao em seu
proprio conteudo. Uma consulta JSONPath pode retornar zero correspondencias, uma, ou muitas, o que
e um contrato fundamentalmente diferente do resolver-ou-falhar de um ponteiro.
A diferenca pratica
Um ponteiro nomeia uma localizacao que voce ja conhece. Uma consulta JSONPath descreve uma condicao e permite que o motor encontre o que a satisfaz. Essa diferenca determina qual se encaixa em um trabalho determinado:
- Voce ja sabe exatamente qual valor quer (“o terceiro elemento do array de endereco de envio”): use um ponteiro. E mais simples, tem um significado unico por documento, e todas as implementacoes concordam com o que ele faz, ja que a RFC deixa pouco espaco para diferencas de dialeto.
- Voce esta procurando valores que correspondam a uma condicao, ou nao conhece
o caminho exato de antemano (“cada objeto com um
statusdefailed, onde quer que apareca”): recorra ao JSONPath. E aqui que as diferencas de dialeto comecam a importar: as implementacoes de JSONPath variam mais do que sugerem os proprios exemplos da RFC 9535, entao uma consulta escrita para uma biblioteca nao e garantida de se comportar de forma identica em outra.
Onde cada um aparece na pratica
As operacoes JSON Patch (RFC 6902) usam exclusivamente ponteiros; cada "path"
em uma operacao add, remove, replace ou move e um ponteiro JSON,
porque uma operacao de patch visa uma localizacao exata por design. A palavra
chave $ref do JSON Schema tambem resolve via sintaxe de ponteiro, pela mesma
razao: uma referencia de schema aponta para uma definicao, nao para um conjunto delas.
JSONPath aparece onde uma pessoa ou ferramenta precisa consultar um documento
interativamente: depurando uma resposta de API grande, extraindo um campo de
registros, ou construindo uma regra que deve corresponder a qualquer documento com uma
forma dada independentemente de onde o campo relevante esta sentado.
Testando ambos
O Avaliador de Ponteiro JSON resolve um ponteiro contra um documento e, em uma busca mal-sucedida, relata onde parou e quais chaves realmente existem naquele ponto, em vez de um simples “nao encontrado”. O Testador JSONPath executa o subconjunto documentado da RFC 9535 com extensoes de funcoes, e a fiche de referencia JSONPath deste blog tem um exemplo elaborado para cada seletor que vale a pena conhecer. Como usar o ponteiro JSON cobre a sintaxe do ponteiro em mais profundidade, incluindo os escapes.