Comparador JSON

Compare dois objetos JSON e visualize as diferenças destacadas.

Nenhum dado sai do seu dispositivo

Sobre a comparação JSON

A comparação JSON (também chamada de diff JSON) identifica as diferenças entre duas estruturas JSON. Diferentemente de um diff de texto simples, uma comparação que entende JSON conhece as chaves e os valores e pode, portanto, indicar exatamente quais propriedades foram adicionadas, removidas ou modificadas · independentemente da ordem das chaves.

Esta ferramenta faz uma comparação profunda e recursiva de dois objetos JSON. Trata objetos aninhados, arrays, strings, números, booleanos e valores null. Todo o processamento é feito localmente no seu navegador.

Uma breve história do JSON

A biografia do JSON é mais curta que a da linguagem de programação média e bem menos dramática. O acrônimo surgiu na State Software, Inc., uma pequena empresa que Douglas Crockford e Chip Morningstar fundaram em março de 2001 para construir o que mais tarde seria chamado de aplicações web Ajax. A primeira mensagem JSON foi enviada em abril de 2001, de um computador na garagem de Morningstar na Bay Area. Crockford não reivindica ter inventado JSON, ele o descolou da sintaxe de objeto literal do JavaScript, deu-lhe um nome e montou um site. Adquiriu json.org em 2002 e postou ali uma gramática em diagrama ferroviário. Por quatro anos o JSON se propagou por boca a boca e um lento gotejar de implementações de bibliotecas. Em dezembro de 2005, o Yahoo! começou a oferecer alguns dos seus serviços web em JSON, o momento que a maioria dos historiadores aponta como a entrada de JSON no mainstream. A padronização veio em ondas: RFC 4627 (julho de 2006), escrita pelo próprio Crockford, com status informacional em vez de standards-track; ECMA-404 primeira edição (outubro de 2013); RFC 7159 (março de 2014), que colocou JSON no Standards Track da IETF e afrouxou a exigência de que o valor de nível superior fosse objeto ou array. As versões atuais são RFC 8259 (dezembro de 2017), agora Internet Standard STD 90, e ECMA-404 segunda edição (dezembro de 2017). Os dois são intencionalmente idênticos em gramática; o texto IETF acrescenta orientação de segurança e interoperabilidade que o texto Ecma omite deliberadamente.

Duas famílias algorítmicas: diff por linha e diff estrutural

A ciência da computação vem pensando em diffs desde os anos 1970. Douglas McIlroy (o mesmo McIlroy que inventou os pipes do Unix) e James W. Hunt escreveram o diff Unix original no início dos anos 1970; veio como parte da 5.ª edição do Unix em 1974, com o algoritmo subjacente documentado no Bell Labs Computing Science Technical Report #41 em junho de 1976. Hunt-McIlroy se baseia no problema da subsequência comum mais longa: encontrar a sequência mais longa de linhas que aparece em ordem em ambas as entradas, e tudo que não estiver nessa sequência é ou uma deleção ou uma inserção. Uma década depois, Eugene W. Myers publicou «An O(ND) Difference Algorithm and Its Variations» em Algorithmica Vol 1, Issue 2 (1986), reformulando o problema como busca de caminho mais curto sobre um «grafo de edição», base para uma implementação Unix diff mais rápida que rodava duas a quatro vezes mais rápida que sua predecessora. Hoje, git diff usa por padrão um algoritmo histograma em LibXDiff, geralmente mais rápido que Myers vanilla e produzindo saída mais legível, especialmente em torno de blocos movidos. Patience diff (Bram Cohen, 2008) é outro refinamento LCS que prioriza linhas-âncora únicas. Todas variações sobre um tema: LCS linha a linha, tratando a entrada como sequência plana de tokens opacos. Nenhum sabe o que é JSON.

A família de diff estrutural adota uma abordagem diferente: percorrer ambas as entradas em paralelo, comparando primitivos por igualdade estrita, computando a união das chaves de objeto (presente-só-na-esquerda é «removido», presente-só-na-direita é «adicionado», presente-em-ambos significa recursão), e percorrendo arrays por índice. Para cada posição, recursão. Se um array é mais longo, os elementos extras são adicionados ou removidos. Mudanças de tipo (número vs string, objeto vs array) tornam-se entradas «tipo mudado». Esse é o algoritmo que jsondiffpatch implementa como caso base, e é o algoritmo que esta ferramenta implementa. Sua força é que a saída tem sentido: cada mudança reportada tem um caminho dentro do documento (user.address.city, items[3].price) e semântica clara. Sua fraqueza é o terceiro passo, comparação de arrays por índice, que produz sem-sentido sempre que um elemento é inserido perto do início de um array longo.

O problema mais difícil do diff JSON: arrays

Suponha que seu JSON «antes» contenha o array ["alpha", "beta", "gamma", "delta"] e seu JSON «depois» contenha ["alpha", "new", "beta", "gamma", "delta"]. Um diff ingênuo baseado em índice reporta quatro mudanças: índice 1 mudou de «beta» para «new»; índice 2 mudou de «gamma» para «beta»; índice 3 mudou de «delta» para «gamma»; índice 4 adicionou «delta». Um humano olhando para isso diria que há uma mudança: uma única inserção no índice 1. Este é o mesmo problema LCS que a família de diff por linha resolveu nos anos 1970, aplicado a arrays de valores JSON em vez de arrays de linhas de texto. jsondiffpatch faz exatamente isso, computa o LCS dos dois arrays e emite inserções e deleções relativas a ele. Para arrays de primitivos isso funciona bem. Para arrays de objetos não: [{id: 1, name: "Alice"}] versus [{id: 1, name: "Alicia"}] não têm subsequência comum por igualdade de referência, então o LCS ingênuo reporta «remover todo o elemento da esquerda, adicionar todo o elemento da direita» quando a verdade é que um campo de um elemento mudou. A solução do jsondiffpatch é o callback objectHash: o chamador fornece uma função que mapeia cada objeto a uma chave de identidade (tipicamente obj => obj.id), e o diff combina elementos do array por identidade em vez de por referência. Este é um problema geral difícil que ninguém resolveu por completo. A ferramenta Absolutool, segundo seu próprio FAQ, compara arrays por índice, não implementa nem LCS nem objectHash. Essa é uma escolha de escopo deliberada para uma pequena ferramenta gratuita: ela é excelente em diffs de objetos e mais fraca em arrays onde elementos foram inseridos ou reordenados.

JSON Patch (RFC 6902): diffs como formato de transporte

RFC 6902, «JavaScript Object Notation (JSON) Patch», foi publicada em abril de 2013. Define o tipo de mídia application/json-patch+json e uma linguagem de patch de seis operações: add, remove, replace, move, copy, test. Um patch é em si um documento JSON, um array de objetos operação, cada um com uma chave op, uma chave path (um JSON Pointer para o local alvo) e um campo valor ou from conforme apropriado. Operações são aplicadas em ordem, atomicamente: se alguma falhar, todo o patch é rejeitado. A sintaxe do path vem de RFC 6901, «JSON Pointer», um documento companheiro publicado no mesmo mês, uma minúscula sintaxe de string de tokens de referência separados por barras (/user/address/city significa «o valor na chave city dentro de address dentro de user»; /items/3 significa «o quarto elemento de items», com índice zero). Como / e ~ são especiais, são escapados para ~1 e ~0 respectivamente (nessa ordem, decodificar ~1 primeiro para evitar bugs de decodificação dupla). JSON Patch é o formato de saída correto para uma ferramenta de diff JSON que quer alimentar o resultado para outra máquina. O método HTTP PATCH (RFC 5789) foi projetado exatamente para esse tipo de payload de atualização parcial. Kubernetes suporta RFC 6902 junto com seu próprio formato strategic-merge-patch. Esta ferramenta não emite atualmente JSON Patch, essa é uma direção de funcionalidade futura, não atual.

JSON Merge Patch (RFC 7396): a alternativa mais simples, com perda

RFC 7396, «JSON Merge Patch», foi publicada em outubro de 2014 por Paul Hoffman e James Snell. Não usa operações nenhuma, o documento patch é simplesmente um objeto JSON parcial que se sobrepõe ao original. Qualquer campo presente no patch sobrescreve o campo correspondente no original; qualquer campo posto a null no patch remove esse campo; qualquer campo ausente do patch fica inalterado; arrays são substituídos por inteiro, nunca mesclados. Merge Patch é conciso e fácil de escrever à mão. O compromisso é a perda de expressividade: não há jeito de pôr o valor de um campo como null literal (porque null significa «remover»); não há jeito de modificar um único elemento de um array (todo o array é substituído); não há jeito de expressar um move ou copy; não há jeito de distinguir «não toquei nesse campo» de «quero colocá-lo no seu valor atual». Para a maioria das atualizações cotidianas de API essas limitações são aceitáveis, por isso Merge Patch é o mais popular dos dois formatos. RFC 6902 ganha em cenários onde alguma das limitações morde. Kubernetes usa ambos os formatos deliberadamente, escolhendo o certo para cada contexto.

Como o diff visual é renderizado

Há três convenções visuais comuns para exibir um diff estrutural. Lado a lado, duas colunas, original à esquerda, modificado à direita, com as linhas correspondentes alinhadas (o layout que esta ferramenta usa para as entradas). Diff unificado inline, uma única coluna mostrando linhas removidas (tipicamente prefixadas com - e coloridas em vermelho), linhas adicionadas (+, verde) e linhas de contexto sem alterações (sem prefixo, texto puro), o layout que git diff usa por padrão. Visão em árvore, renderizar o JSON como uma árvore colapsável, com nós alterados destacados e nós sem alteração dobrados. Convenções de cor são notavelmente consistentes no ecossistema: verde para adições, vermelho para remoções, amarelo ou âmbar para valores alterados, cinza neutro para sem alteração. Esta ferramenta segue a convenção exatamente: verde claro para adições, vermelho claro para remoções, amarelo claro para mudanças. A maioria dos usuários reconhecerá as cores do GitHub, GitLab, BitBucket, qualquer visão de diff de IDE e dezenas de ferramentas online.

Usos comuns

Casos-limite que vale a pena conhecer

Precisão numérica. RFC 8259 diz que números JSON são de precisão arbitrária e não põe limite superior em quantos dígitos um número pode ter. JavaScript, porém, parseia cada número como um double IEEE 754 de 64 bits. Acima de Number.MAX_SAFE_INTEGER (253 − 1 = 9.007.199.254.740.991), inteiros podem perder precisão silenciosamente ao ir e voltar por um diff baseado em JavaScript. O mesmo problema afeta a vírgula flutuante, 0.1 + 0.2 não é famosamente exatamente 0.3 em IEEE 754. JSON estrito também proíbe vírgulas finais e comentários; ambos são erros de sintaxe pela RFC 8259. JSON5 (json5.org) é um superconjunto formal permitindo comentários, vírgulas finais, aspas simples, chaves sem aspas, números hex, pontos decimais iniciais/finais e Infinity/NaN. JSONC é o modo «JSON with Comments» da Microsoft usado nos arquivos de configurações do VS Code. Esta ferramenta usa JSON.parse() e portanto rejeitará ambos, remova comentários e vírgulas finais antes de colar.

Strings de data. JSON não tem tipo data nativo. Datas são tipicamente codificadas como strings, sendo o padrão de fato ISO 8601 (e especificamente o perfil RFC 3339 que a maioria das APIs de internet usa): YYYY-MM-DDTHH:MM:SS[.fff]Z. Um diff que compara datas como strings reportará 2024-01-01T00:00:00Z e 2024-01-01T00:00:00.000Z como diferentes, mesmo que representem o mesmo instante, porque as strings diferem. Chaves duplicadas. RFC 8259 §4 diz «nomes dentro de um objeto DEVERIAM ser únicos», o DEVERIAM é normativamente mais fraco que DEVEM. O JSON.parse() do JavaScript aceita chaves duplicadas e silenciosamente fica com a última; outros parsers podem ficar com a primeira ou levantar um erro. null vs ausente. {"a": null} e {} são valores JSON diferentes. Esta ferramenta reporta o primeiro como «a chave a tem valor null» e o segundo como «sem chave a», eles são corretamente distinguidos. O tratamento de null pelo JSON Merge Patch como sinal de remoção é uma admissão no nível de formato de que a distinção é real e delicada.

O ecossistema em 2026

O diff JSON open-source é dominado por um punhado de bibliotecas. jsondiffpatch de Benjamin Eidelman, publicada pela primeira vez em 2012, é a biblioteca JavaScript de fato: ~5k estrelas no GitHub, suporta objectHash, arrays LCS, patches reversos e um formatador HTML visual. json-diff de Andrey Tarantsov é a ferramenta CLI Node canônica, com o mesmo nome compartilhado por implementações paralelas em Python, Go e Rust. DeepDiff de Sep Dehpour é a biblioteca Python dominante, diff recursivo com opções para ignorar ordem, ignorar mudanças de tipo numérico e uma porção de controles finos. O diff JsonNode de Jackson (Java) na Linux Foundation é a escolha padrão JVM. jq não tem comando diff nativo mas sua família de operadores = e // pode expressar comparações estruturais simples. O diff integrado do VS Code lida com JSON via modo texto; a extensão JSON Tools adiciona comparação JSON-aware. Ferramentas online como Diffchecker oferecem modos JSON que são essencialmente o mesmo passeio recursivo que esta ferramenta implementa, frequentemente em camadas sobre as mesmas bibliotecas.

Por que só-navegador importa aqui

Diffear dois payloads JSON em um servidor exige enviar ambos. Para exemplos comuns de dados públicos, é inofensivo. Para respostas de API que contêm tokens de autenticação, PII de clientes, registros internos de funcionários, segredos de configuração ou dados de produto não lançados, não é. Mesmo depois que o diff termina, esses payloads ficam em logs do servidor, possivelmente num cache CDN, possivelmente num pipeline de analytics, possivelmente num backup. Um diff só-navegador nunca transmite, o JSON é parseado e percorrido inteiramente na sua aba. Você pode verificar abrindo a aba Network do DevTools ao clicar em Compare; não há requisições saindo. Para comparar respostas de API contra uma linha base, depurar deriva de configuração entre ambientes ou auditar mudanças em um lockfile que contém URLs de pacotes internos, «o JSON nunca deixa o meu dispositivo» é a arquitetura que torna a ferramenta segura de usar em dados de produção reais.

Perguntas frequentes

A ordem das chaves afeta a comparação ?

Não. Os objetos JSON são não ordenados segundo a especificação, portanto {"a":1, "b":2} e {"b":2, "a":1} são tratados como idênticos. Apenas as diferenças reais de valores são sinalizadas.

Como os arrays são comparados ?

Os arrays são comparados por índice. Se o array no índice 2 difere entre as duas entradas, esse índice específico é sinalizado. Os elementos adicionados ou removidos no fim do array também são detectados.

O que acontece com objetos profundamente aninhados ?

A comparação é totalmente recursiva. Objetos e arrays aninhados em qualquer profundidade são comparados propriedade por propriedade. A saída exibe o caminho completo de cada diferença (por ex. « user.address.city »).

Por que minha comparação de inteiro grande parece errada?

JavaScript parseia cada número JSON como um double IEEE 754 de 64 bits. Acima de Number.MAX_SAFE_INTEGER (253 − 1 = 9.007.199.254.740.991), inteiros podem perder precisão silenciosamente. Então um arquivo JSON contendo 9007199254740993 pode comparar como idêntico a um contendo 9007199254740992. Essa é uma limitação da representação numérica subjacente, não da ferramenta de diff. Se você está diffeando dados que contêm IDs de 64 bits (IDs snowflake do Twitter, IDs do Discord, chaves grandes de banco), faça seu serializador emiti-los como strings em vez de números. Comparação de vírgula flutuante tem a mesma ressalva: 0.1 + 0.2 não é famosamente exatamente 0.3 em IEEE 754.

Posso comparar JSON5 ou JSONC (JSON com comentários)?

Não diretamente. Esta ferramenta usa o JSON.parse() integrado do navegador, que segue estritamente a RFC 8259, comentários, vírgulas finais, strings entre aspas simples e chaves sem aspas são erros de sintaxe. Se sua entrada for JSON5 (json5.org) ou JSONC estilo VS Code, remova primeiro os comentários e vírgulas finais, ou passe por uma ferramenta como jsonc-parser para converter para JSON estrito antes de colar.

Meu JSON é enviado para um servidor?

Não. A comparação roda inteiramente no seu navegador via JavaScript. O JSON colado nunca cruza a rede, verifique na aba Network do DevTools ao clicar em Compare, ou coloque a página offline após carregar e confirme que o diff continua funcionando. Seguro para comparar respostas de API com tokens de autenticação, arquivos de configuração com segredos ou exports de banco contendo PII de clientes.

Ferramentas relacionadas