Erros comuns em JSON e como corrigi-los
O JSON é o formato que muitas APIs, arquivos de configuração e aplicativos web usam para trocar dados, e a gramática dele cabe em uma única página. É também por isso que ele não perdoa: um texto ou é JSON válido ou não é, e uma única vírgula fora do lugar basta para que um parser rejeite tudo. A maioria dos erros vem dos mesmos poucos hábitos, muitos deles trazidos do JavaScript ou de outras linguagens. Este guia lista as regras, os erros que mais as violam, como ler a mensagem de erro e alguns casos que são JSON válido, mas ainda causam problemas.
As regras que o JSON realmente tem
As definições atuais são a RFC 8259, publicada em dezembro de 2017, e a ECMA-404. As duas descrevem a mesma sintaxe:
- As strings, incluindo todos os nomes de propriedade, usam aspas duplas. Aspas simples não são permitidas.
- Os valores são strings, números, objetos, arrays ou um de três literais: true, false e null, sempre em minúsculas.
- Os itens de objetos e arrays são separados por vírgulas, sem vírgula depois do último.
- Os números são escritos em decimal, sem zeros à esquerda, sem sinal de mais e sem NaN nem Infinity.
- Dentro de uma string, a aspa dupla, a barra invertida e os caracteres de controle, como a quebra de linha, precisam ser escapados.
- Não existe sintaxe para comentários.
Entre os tokens, só quatro caracteres de espaço em branco são permitidos: espaço, tabulação, avanço de linha e retorno de carro.
Os erros mais comuns
Cada um destes é rejeitado por um parser padrão. A correção está na descrição.
{"name": "Ana",}Vírgula no final: remova a vírgula depois do último item de um objeto ou array.{'name': 'Ana'}Aspas simples: use aspas duplas nos nomes de propriedade e nas strings.{name: "Ana"}Nome de propriedade sem aspas: todo nome precisa ser uma string entre aspas duplas.{"a": 1 "b": 2}Vírgula faltando entre dois itens, muitas vezes depois de copiar e juntar linhas.{“name”: “Ana”}Aspas tipográficas, que processadores de texto e aplicativos de chat inserem automaticamente: substitua-as por aspas retas ".{"note": 1 // total}Comentários não fazem parte do JSON: remova-os ou passe a anotação para uma propriedade.{"active": True}Literais com inicial maiúscula: escreva true, false e null em minúsculas.{"value": undefined}undefined, NaN e Infinity existem em JavaScript, mas não em JSON: use null ou uma string.{"code": 007}Zeros à esquerda não são permitidos em números: escreva 7, ou "007" como string se os zeros importarem.{"path": "C:\Users"}Uma barra invertida sozinha inicia uma sequência de escape, e \U não é uma delas. Pior: C:\new seria aceito e lido como C:, uma quebra de linha e ew. Escreva \\ para uma barra invertida literal.{"items": [1, 2}Uma chave ou um colchete que nunca se fecha, ou que se fecha com o caractere errado: todo { precisa de um } e todo [ precisa de um ].
Lendo a mensagem de erro
O parser lê o texto da esquerda para a direita e para no primeiro caractere que não consegue aceitar; por isso, a posição na mensagem de erro é onde ele desistiu, o que muitas vezes fica logo depois do erro de verdade. Com uma vírgula no final, o parser reclama da chave de fechamento, porque depois de uma vírgula ele espera outro nome de propriedade. Com uma chave ou um colchete faltando, o erro pode aparecer bem no fim do texto, longe do lugar em que o caractere que falta deveria estar.
O texto das mensagens varia entre navegadores e linguagens, e muitas delas indicam uma posição, embora nem todas, seja como uma contagem de caracteres desde o início, seja como linha e coluna. Por exemplo, o motor JavaScript do Chrome informa {"name":"Ana",} assim:
Expected double-quoted property name in JSON at position 14 (line 1 column 15)Contando a partir de 0, a posição 14 é a chave de fechamento; a vírgula que causou o erro está um caractere antes.
Quando a posição não for óbvia, olhe o caractere logo antes dela e confira se toda chave, todo colchete e toda aspa abertos antes desse ponto têm o seu par. Um editor que destaca os pares de chaves e colchetes muitas vezes torna fácil encontrar o que está faltando.
JSON válido que ainda causa problemas
- Números grandes. O JSON em si não impõe limite, mas o JavaScript, e muitos parsers de JSON em outras linguagens, guardam números como ponto flutuante de 64 bits, que só garante inteiros exatos até 9.007.199.254.740.991. Em JavaScript, JSON.parse transforma 9007199254740993 em 9007199254740992 sem nenhum aviso. IDs grandes ficam mais seguros como strings.
- Nomes de propriedade duplicados. A RFC 8259 diz que os nomes deveriam ser únicos e que o software que recebe duplicatas se comporta de forma imprevisível. O JavaScript fica com o último valor: {"a": 1, "a": 2} vira {"a": 2}.
- Uma marca de ordem de bytes. Alguns editores salvam arquivos UTF-8 com um caractere U+FEFF invisível no início. A RFC 8259 proíbe acrescentá-lo a um JSON enviado pela rede, e o JSON.parse do JavaScript rejeita textos que comecem com ele.
- Um valor solto no nível mais externo. Os padrões atuais (a ECMA-404 e, desde 2014, a RFC 7159 e as que vieram depois) permitem que um texto JSON seja qualquer valor, como "hello" ou 42, mas a RFC 4627, anterior, de 2006, exigia um objeto ou um array, e alguns parsers mais antigos ainda exigem.
JSON não é JavaScript
A sintaxe do JSON foi tirada dos literais de objeto do JavaScript, e é por isso que os dois se confundem com tanta facilidade. Um literal de objeto JavaScript aceita aspas simples, nomes sem aspas, vírgulas no final, comentários e valores como undefined; o JSON não aceita nenhum deles. Por isso, um código que funciona quando colado em um script pode falhar como arquivo JSON.
Algumas ferramentas aceitam formatos estendidos, como o JSON5 ou o “JSON com comentários” usado em arquivos de configuração. Eles são práticos onde há suporte a eles, mas não são JSON, e um parser padrão, incluindo o formatador do nTools, vai rejeitá-los.
Perguntas frequentes
O JSON pode ter comentários?
Não. A especificação não tem sintaxe de comentário. Se você precisar de observações nos dados, coloque-as em uma propriedade como "_comment" ou use um formato que permita comentários, onde as ferramentas derem suporte a ele.
Por que meu JSON funciona no JavaScript, mas falha em um validador?
Porque um literal de objeto JavaScript permite coisas que o JSON não permite, como aspas simples, vírgulas no final e nomes sem aspas. Colado em um código, ele roda; salvo como JSON, é inválido.
Como mantenho exato um número muito grande?
Envie-o como string, por exemplo "9007199254740993", e converta-o no lado que recebe com um tipo capaz de representá-lo, como o BigInt, em JavaScript.
O formatador do nTools envia meu JSON para algum lugar?
Não. Ele é analisado e formatado no seu navegador e, quando o navegador informa uma posição, o formatador a mostra como linha e coluna.
Guias relacionados
- Endereços IP explicados: IPv4, IPv6 e as faixas reservadas
- Sub-redes e CIDR explicados: prefixos, máscaras e hosts utilizáveis
- Registros DNS explicados: A, AAAA, CNAME, MX, TXT e NS
- Timestamps Unix e fusos horários explicados
- Formatos de imagem explicados: JPEG, PNG, WebP, AVIF e HEIC
- Força de senhas explicada: comprimento, entropia e frases-senha
- UUIDs explicados: v4, v7 e como escolher a versão certa
- QR codes explicados: capacidade, correção de erros e tamanho de impressão
- Porcentagens e IVA explicados: somar, tirar e acumular
- Edição de PDFs no navegador: o que se mantém ao juntar, dividir e converter