Também disponível em: English · Español · Français · العربية
JSON Patch: aplique operações da RFC 6902 passo a passo
Rode um patch contra um documento, veja o resultado depois de cada operação e descubra o que uma falha realmente deixa para trás.
O que é JSON Patch
JSON Patch é um formato pequeno para descrever mudanças num documento JSON em vez de mandar o documento inteiro. Um patch é um array de operações, e cada uma diz o que fazer e onde: add, remove, replace, move, copy e test. A RFC 6902 define as seis em uma oito páginas, e cada local é escrito como um JSON Pointer, o formato irmão que nomeia exatamente um lugar dentro de um documento.
Ele existe porque mandar um documento inteiro para mudar um campo é desperdício e ainda por cima é ambíguo: dois clientes fazendo isso se sobrescrevem sem perceber. Um patch diz o que mudou, o que ocupa menos e é específico o bastante para ser recusado se o documento já não for o mesmo. É para isso que serve a sexta operação: test não muda nada, ela afirma, e um patch que começa com um test é uma mudança que se recusa a ser aplicada ao documento errado.
Esta página roda um patch contra um documento e mostra o resultado depois de cada operação, não só no fim. E isso importa mais do que parece, pelo motivo de que trata a seção depois da próxima.
Como usar
- Cole o documento. Ele nunca é modificado no lugar: cada operação trabalha sobre uma cópia, então o seu documento fica intacto faça o patch o que fizer.
- Cole o patch. Um array de operações. Os botões de exemplo carregam cinco casos: um test que falha no meio, uma inserção em array, um test usado como salvaguarda, um move que a norma proíbe e um índice além do fim de um array.
- Leia o rastro. Cada linha é uma operação, e você pode expandir qualquer uma para ver o documento inteiro como estava naquele momento. Uma falha nomeia a regra específica em vez de não dizer nada.
Um JSON Patch não é atômico, e a norma não diz que é
Todo mundo sabe que um patch que falha deixa o documento intacto. É a primeira coisa que contam sobre o formato, e não é o que a RFC 6902 diz.
A seção 5 diz que, diante de uma falha, a avaliação deveria terminar e a aplicação do patch inteiro não deve ser considerada bem-sucedida. Leia com atenção: é uma afirmação sobre o veredicto, sobre se o patch conta como aplicado. Não diz nada sobre desfazer as operações que já rodaram. A atomicidade que todo mundo cita chega uma frase depois e vem de outro lugar: uma nota dizendo que o método HTTP PATCH é atômico, conforme outro documento, o que define esse método.
Então a garantia é do transporte, não do formato. Mande um patch por HTTP PATCH e o servidor é obrigado a aplicar tudo ou nada. Entregue o mesmo patch a uma biblioteca dentro do seu processo e ficar com um objeto meio modificado é assunto dela, não algo que a norma resolva por você. O exemplo da própria norma é um patch de duas operações cujo test falha em segundo, e ela diz que o documento acaba sem mudanças — porque está descrevendo o caso HTTP.
É por isso que esta ferramenta mostra todos os estados intermediários. Quando um patch falha aqui, ela descarta o resultado e avisa, o que é uma escolha e não uma regra; e mostra no que o documento já tinha se transformado, que é exatamente o que uma ferramenta que só imprime a resposta final esconde de você.
Três regras que surpreendem
Adicionar num array insere, não sobrescreve. Aponte o add para o índice um de um array de três elementos e você fica com quatro, com tudo do índice um em diante deslocado para a direita. Se você queria sobrescrever, isso é replace. O índice pode ser igual ao tamanho, o que acrescenta ao final, mas qualquer coisa além disso é erro e não uma escrita esparsa — e a sintaxe de ponteiros tem um hífen que significa depois do último elemento, o que diz acrescente ao final bem mais claro do que um número.
A mesma operação esconde outra armadilha, mais silenciosa. Adicionar um array como valor o insere inteiro como um único elemento, então uma lista de um mais um array de dois vira uma lista de dois, sendo o segundo ele mesmo uma lista. A norma inclui isso como exemplo à parte, o que costuma ser sinal de que as pessoas esperavam a outra coisa.
Move traz uma regra sem equivalente nas demais operações: a origem não pode ser prefixo próprio do destino ou, nas palavras da própria norma, um local não pode ser movido para dentro de um de seus filhos. É óbvio assim que se diz e facílimo de escrever sem querer quando os caminhos são longos.
E test compara tipos além de valores. O número dez e a string dez são diferentes, e um test que confronte um com o outro falha. É o comportamento que você quer de uma precondição, mas pega quem vem de um formulário ou de uma query string, onde tudo chegou como texto.
Limitações honestas
Isto aplica patches; não os gera. Produzir o patch mínimo entre dois documentos é outro problema, com várias respostas defensáveis, e a norma não define nenhuma.
Há um exemplo da norma que esta ferramenta não consegue rodar, e vale saber por quê. É um patch cujo objeto de operação contém o mesmo membro duas vezes — op aparece como add e como remove — e a norma observa que o JSON apenas diz que nomes de membro deveriam ser únicos, sem tratamento padrão para duplicatas. Qualquer parser de JavaScript resolve isso em silêncio ficando com o último, de modo que o defeito que o exemplo quer descrever é destruído antes de um motor de patch ver o documento. É uma propriedade do parser, não do formato, e nenhuma implementação que receba JSON já parseado consegue detectá-lo.
Por fim, esta ferramenta descarta o resultado quando qualquer operação falha. É deliberado e é o padrão mais seguro, mas é uma decisão desta página, não algo que o formato imponha — e é justamente por isso que o documento pela metade aparece ao lado em vez de ser jogado fora em silêncio.
Por que é grátis?
Percorrer um documento e aplicar um punhado de operações são algumas centenas de linhas de manipulação de strings e arrays, e o seu navegador faz isso enquanto você digita. Nenhum servidor vê o seu JSON, então não há nada a medir nem conta a criar.
Nada é enviado. O que você colar fica nesta aba.