Tutorial de JSON: sintaxe, regras e como trabalhar com JSON em JavaScript e Python
JSON é o formato de troca de dados mais simples e mais usado; com poucas regras curtas e duas funções em cada linguagem, você consegue ler, criar e guardar qualquer dado.
Se você trabalha com APIs, aplicativos mobile ou até com o arquivo de configuração de um projeto, mais cedo ou mais tarde vai topar com JSON. JSON é um formato de texto para guardar e transportar dados que as pessoas conseguem ler e que qualquer linguagem de programação processa com facilidade. Este tutorial começa pela definição e pelas regras de sintaxe, passa por um exemplo real, segue para a leitura e a escrita de JSON em JavaScript e Python, com atenção especial a letras acentuadas e outros textos fora do inglês, e termina com os erros mais comuns e como localizá-los com o Formatador de JSON. Todo o código desta página foi executado, e as saídas são reais.
O que é JSON?
JSON é a sigla de JavaScript Object Notation. A sintaxe vem do jeito como os objetos são escritos em JavaScript, mas o formato não depende de nenhuma linguagem: Python, PHP, Java, C#, Go e praticamente todas as outras linguagens têm ferramentas prontas para trabalhar com ele. O JSON é definido pelos padrões RFC 8259 e ECMA-404, os arquivos usam a extensão .json e o tipo de mídia na web é application/json. Usos comuns:
- APIs web: a maioria dos serviços modernos envia requisições e respostas em JSON.
- Arquivos de configuração: como o
package.jsonem projetos Node.js ou ocomposer.jsonno PHP. - Armazenamento de dados: no
localStoragedo navegador, nas colunas JSON de bancos de dados como PostgreSQL e MySQL e em bancos de dados de documentos.
Regras de sintaxe do JSON
Todo documento JSON é construído a partir de seis tipos de valor, que podem ser aninhados uns dentro dos outros:
| Tipo | Exemplo | Descrição |
|---|---|---|
| object | {"city": "Lisbon"} | Pares de chave e valor entre chaves |
| array | [1, 2, 3] | Uma lista ordenada de valores entre colchetes |
| string | "hello" | Texto entre aspas duplas |
| number | 42, -3.5, 1.2e6 | Inteiro ou decimal, sem aspas |
| boolean | true, false | Só em minúsculas |
| null | null | A ausência de valor |
Estas são as regras por trás da maioria dos erros:
- As chaves são sempre strings entre aspas duplas:
{"name": "Ali"}está correto e{name: "Ali"}não está. - Só aspas duplas são permitidas;
'Ali'entre aspas simples não é JSON válido. - Vírgula no final não é permitida: nenhuma vírgula pode vir depois do último membro de um objeto ou de um array.
- Não existem comentários: nem
//nem/* */. - Valores específicos de uma linguagem não são permitidos:
undefined,NaN,Infinity,TrueeNonenão são JSON válido. - Números não podem começar com zero:
012é inválido. Por isso, números de telefone, códigos postais e identificadores parecidos devem ser escritos como strings, como"0123456789"; assim o zero à esquerda também é preservado. - Caracteres especiais dentro de strings são escapados:
\"para aspas duplas,\\para barra invertida,\npara quebra de linha e\uXXXXpara qualquer caractere Unicode. - Espaços e quebras de linha entre as partes não fazem diferença; é por isso que o JSON pode ser escrito tanto compacto, em uma única linha, quanto bem indentado.
Um exemplo real: o pedido de uma loja virtual
{
"orderId": 10245,
"createdAt": "2026-09-17T10:30:00Z",
"customer": {
"name": "Maria",
"phone": "0123456789",
"city": "Lisbon"
},
"items": [
{ "title": "Python for Beginners", "price": 32, "qty": 1 },
{ "title": "Wireless Mouse", "price": 45, "qty": 2 }
],
"paid": true,
"discountCode": null
}
Este exemplo mostra todos os tipos de valor. customer é um objeto aninhado e items é um array de objetos. Os preços são números, mas o telefone é uma string, para que o zero à esquerda seja mantido. O JSON não tem um tipo "data", então o horário do pedido é uma string no formato padrão ISO 8601. E discountCode usa null para dizer que este pedido não teve cupom de desconto. Para ler o preço do segundo item, você escreve order.items[1].price em JavaScript e order["items"][1]["price"] em Python.
Trabalhando com JSON em JavaScript
O JavaScript tem duas funções nativas que bastam para a maioria das tarefas: JSON.parse transforma texto JSON em objeto, e JSON.stringify transforma um objeto em texto JSON.
Ler JSON com JSON.parse
const text = '{"name": "Maria", "age": 28, "skills": ["JavaScript", "Python"], "active": true}';
const user = JSON.parse(text);
console.log(user.name); // Maria
console.log(user.skills[0]); // JavaScript
console.log(user.active); // true
Criar JSON com JSON.stringify
const product = { title: "Café Guide", price: 32, tags: ["travel", "bestseller"], discount: null };
console.log(JSON.stringify(product));
console.log(JSON.stringify(product, null, 2));
A primeira chamada gera JSON compacto, em uma linha, ideal para enviar pela rede; a segunda, com 2 como terceiro argumento, gera uma saída legível, indentada com dois espaços. O segundo argumento serve para filtrar ou transformar valores e normalmente fica como null. A saída:
{"title":"Café Guide","price":32,"tags":["travel","bestseller"],"discount":null}
{
"title": "Café Guide",
"price": 32,
"tags": [
"travel",
"bestseller"
],
"discount": null
}
Letras acentuadas e outros textos não ASCII ficam exatamente como são na saída de JSON.stringify; eles não viram escapes \u.
Buscar JSON de uma API e guardar no localStorage
async function loadProduct() {
const res = await fetch("https://api.example.com/products/1");
return await res.json();
}
localStorage.setItem("cart", JSON.stringify({ items: [101, 205] }));
const cart = JSON.parse(localStorage.getItem("cart"));
console.log(cart.items.length); // 2
O método res.json() já faz o parse da resposta e devolve um objeto; não passe o resultado dele de novo para JSON.parse. O localStorage só guarda strings, então o objeto é convertido com JSON.stringify ao ser salvo e com JSON.parse ao ser lido.
Valores que o JSON.stringify altera
const data = { a: undefined, b: () => 1, c: NaN, d: new Date(Date.UTC(2026, 8, 17)) };
console.log(JSON.stringify(data));
// {"c":null,"d":"2026-09-17T00:00:00.000Z"}
Chaves cujo valor é undefined ou uma função são descartadas sem aviso, NaN e Infinity viram null, e uma data vira uma string ISO. Quando você faz o parse do resultado de novo, a data continua sendo string e não volta a ser um Date sozinha.
Tratando erros
try {
JSON.parse("{'name': 'Ali'}");
} catch (err) {
console.log(err.name); // SyntaxError
console.log(err.message); // Expected property name or '}' in JSON at position 1 (line 1 column 2)
}
Qualquer texto inválido lança um SyntaxError, então processe dados vindos de fora dentro de try...catch. A mensagem acima é a saída do Node.js, igual à do Chrome; o Firefox e o Safari relatam o mesmo erro com outras palavras.
Trabalhando com JSON em Python
Em Python, o módulo padrão json faz todo o trabalho, e não há nada para instalar. Ele tem quatro funções principais: json.loads e json.dumps trabalham com strings, enquanto json.load e json.dump trabalham direto com arquivos; o s das duas primeiras vem de string.
Transformar uma string JSON em dicionário
import json
text = '{"name": "Maria", "age": 28, "skills": ["JavaScript", "Python"], "active": true}'
user = json.loads(text)
print(user["name"]) # Maria
print(type(user)) # <class 'dict'>
print(user["active"]) # True
| JSON | Python | JavaScript |
|---|---|---|
| object | dict | Object |
| array | list | Array |
| string | str | String |
| number | int ou float | Number |
true / false | True / False | true / false |
null | None | null |
Converter dados para JSON e o problema dos textos não ASCII
product = {"title": "Café Guide", "price": 32, "tags": ["travel", "bestseller"], "discount": None}
print(json.dumps(product))
print(json.dumps(product, ensure_ascii=False, indent=2))
A primeira linha da saída pode surpreender:
{"title": "Caf\u00e9 Guide", "price": 32, "tags": ["travel", "bestseller"], "discount": null}
Por padrão, json.dumps escreve todo caractere não ASCII na forma \uXXXX, então é vira \u00e9, e um texto em qualquer outro alfabeto é escapado caractere por caractere do mesmo jeito. Em português, isso atinge cada acento e cada cedilha. Essa saída é válida e qualquer programa a lê corretamente, mas as pessoas não conseguem lê-la, e ela ocupa mais espaço. Com ensure_ascii=False o texto é escrito exatamente como é, e indent=2 organiza a saída igual ao exemplo em JavaScript.
Ler e gravar arquivos JSON
with open("product.json", "w", encoding="utf-8") as f:
json.dump(product, f, ensure_ascii=False, indent=2)
with open("product.json", encoding="utf-8") as f:
loaded = json.load(f)
print(loaded["tags"][0]) # travel
Dois pontos importantes: passe ensure_ascii=False também para json.dump, e sempre abra o arquivo com encoding="utf-8". No Windows, se você não especificar a codificação, o Python pode recorrer à codificação padrão do sistema, que não é UTF-8; o resultado é um UnicodeEncodeError ou um arquivo cheio de caracteres embaralhados.
A saída do print não é JSON
print(product)
# {'title': 'Café Guide', 'price': 32, 'tags': ['travel', 'bestseller'], 'discount': None}
Um erro muito comum é colar em algum lugar, como se fosse JSON, a saída do print de um dicionário. Esse texto é a representação própria do Python para os dados: tem aspas simples e None em vez de null, então nenhum parser de JSON vai aceitá-lo. Para criar JSON, use sempre json.dumps.
Tratando erros em Python
try:
json.loads("{'name': 'Ali'}")
except json.JSONDecodeError as e:
print(e) # Expecting property name enclosed in double quotes: line 1 column 2 (char 1)
json.JSONDecodeError é uma subclasse de ValueError, e os atributos lineno, colno e pos indicam a posição do erro. Se você usa a biblioteca requests, response.json() faz a mesma conversão para a resposta de uma API. Uma diferença sutil: por padrão, o Python aceita NaN na entrada e também o escreve na saída, embora esse valor não seja JSON padrão; para impedir isso, passe allow_nan=False para json.dumps.
Erros comuns de JSON e o que as mensagens significam
| Erro | Exemplo inválido | Mensagem no JavaScript (Node.js e Chrome) | Mensagem no Python |
|---|---|---|---|
| Aspas simples ou chave sem aspas | {'name': 'Ali'} | Expected property name or '}' | Expecting property name enclosed in double quotes |
| Vírgula sobrando no fim de um objeto | {"a": 1,} | Expected double-quoted property name | Python 3.14: Illegal trailing comma before end of object; Python 3.12: Expecting property name enclosed in double quotes |
| Vírgula sobrando no fim de um array | [1, 2,] | Unexpected token ']' | Python 3.14: Illegal trailing comma before end of array; Python 3.12: Expecting value |
| Vírgula faltando, ou comentário depois de um valor | {"a": 1 "b": 2} | Expected ',' or '}' after property value | Expecting ',' delimiter |
| Um valor de Python ou de JavaScript | {"a": True} | Unexpected token 'T' | Expecting value |
| Número com zero à esquerda | {"phone": 0123456789} | Unexpected number | Expecting ',' delimiter |
| String não fechada | {"a": "x} | Unterminated string | Unterminated string starting at |
| Entrada vazia | Texto vazio | Unexpected end of JSON input | Expecting value |
As mensagens costumam trazer também a posição, como position 8 ou line 1 column 9, e o problema real muitas vezes está logo antes desse ponto. Se uma mensagem do JavaScript começa com Unexpected token '<', provavelmente você recebeu uma página HTML em vez de JSON, por exemplo uma página de erro 404 ou uma tela de login; o guia sobre o erro Unexpected token explica esse caso passo a passo. Um arquivo salvo com BOM gera o erro Unexpected UTF-8 BOM no Python; abra-o com encoding="utf-8-sig" ou salve-o sem o BOM.
Formatar e validar com o Formatador de JSON
Quando um JSON longo chega em uma única linha, ou você não consegue descobrir por que ele não passa no parse, o Formatador de JSON é o caminho mais rápido. A ferramenta usa o próprio parser de JSON do navegador, e os dados nunca saem do seu navegador, então você pode inspecionar com segurança respostas de API que contêm tokens ou dados de usuários. O passo a passo:
- Cole o JSON na caixa JSON de entrada; ele é formatado na hora, e o botão Formatar faz o mesmo.
- Escolha a indentação no menu Indentação: 2 espaços, 4 espaços ou Tabulação.
- Se o JSON for inválido, uma mensagem começando com
JSON inválido:mostra o texto de erro do navegador, que normalmente inclui a posição do problema; use a tabela acima para entender o que ele significa e corrigir. - A aba Árvore mostra os dados como uma árvore recolhível, e Expandir tudo e Recolher tudo abrem ou fecham todos os ramos; muito prático para encontrar uma chave em uma resposta grande.
- Para enviar ou guardar os dados de forma compacta, Minificar remove todos os espaços e quebras de linha. Copie o resultado com Copiar.
Quando o seu código precisa de tipos para o JSON que recebe, o JSON para Tipos gera definições em TypeScript, Go ou Python a partir de um exemplo; o guia sobre como tipar respostas de API em TypeScript mostra o passo a passo.