All articles
37 articles · updated weekly See our Tools
All articles
Tutoriais

O que é JSON e como esse formato funciona

Entenda o que é JSON, seus seis tipos de dados, sintaxe obrigatória e onde o formato é usado — com exemplos reais em JavaScript, Python e Go.

COVER · Tutoriais

Você abre a resposta de uma API, vê um monte de chaves, colchetes e dois-pontos, e pensa: "o que é isso?" É JSON. Formato de texto simples que virou o padrão não-oficial de troca de dados na web — não por decreto, mas porque alguém precisava de algo mais legível que XML e mais portável que CSV.

O que é JSON

JSON significa JavaScript Object Notation. O nome engana: não é exclusivo do JavaScript. Qualquer linguagem moderna — Python, Go, PHP, Java, Rust — consegue ler e escrever JSON com suporte nativo ou uma biblioteca pequena.

É um formato de texto. Isso significa que você pode abrir qualquer resposta JSON no bloco de notas e ler. Sem bytes especiais, sem cabeçalhos binários. O que você vê é o que está lá.

O padrão está definido na RFC 8259 e no site json.org. A especificação inteira cabe em uma página — esse é um dos motivos do sucesso.

Sintaxe básica

JSON é construído com dois tipos de estrutura: objetos (chave-valor) e arrays (lista ordenada).

Um objeto:

{
  "nome": "Rafael",
  "idade": 31,
  "ativo": true
}

Um array:

["São Paulo", "Rio de Janeiro", "Belo Horizonte"]

Arrays e objetos podem ser combinados livremente:

{
  "usuario": "rafael",
  "cidades": ["São Paulo", "Campinas"],
  "perfil": {
    "plano": "pro",
    "trial": false
  }
}

Tipos de dados

JSON suporta exatamente seis tipos. Não tem data, não tem função, não tem classe. Seis tipos:

Tipo Exemplo Observação
string "texto" Sempre aspas duplas
number 42, 3.14, -7 Sem distinção int/float
boolean true, false Minúsculo, sem aspas
null null Minúsculo
object { "chave": "valor" } Chaves sempre strings
array [1, 2, 3] Valores de qualquer tipo

Alguns detalhes que pegam iniciantes:

  • Strings precisam de aspas duplas. Aspas simples são inválidas em JSON.
  • Chaves de objeto são sempre strings: { "id": 1 }, nunca { id: 1 }.
  • Não existe tipo Date. Data vira string — geralmente ISO 8601: "2024-03-15T10:00:00Z".
  • Não existe undefined. Se um campo não existe, ele simplesmente não está no JSON — ou está como null.
  • Sem trailing comma. { "a": 1, } é inválido. Isso incomoda bastante quem vem de JavaScript moderno.

Onde JSON é usado

Em qualquer ponto onde dois sistemas precisam trocar dados:

APIs REST: o corpo de um POST com dados de login, a resposta de um endpoint que retorna uma lista de usuários, erros de validação com campo e mensagem — tudo JSON.

Arquivos de configuração: package.json no Node.js, tsconfig.json, composer.json no PHP, .eslintrc, extensões do VS Code. Boa parte do ecossistema JavaScript usa JSON como formato de config.

LocalStorage e cookies: dados simples no browser quase sempre são serializados como JSON antes de guardar e deserializados na leitura.

Logs e eventos: sistemas de observabilidade como Datadog, Elastic e Loki esperam logs em formato JSON estruturado. Muito mais fácil de filtrar do que texto livre.

Banco de dados: PostgreSQL tem tipo jsonb nativo com indexação. MongoDB armazena documentos em BSON (Binary JSON). Muitos bancos relacionais modernos suportam colunas JSON.

Como ler e escrever JSON em código

Em JavaScript e TypeScript:

// Parse: string JSON → objeto
const dados = JSON.parse('{"nome":"Rafael","idade":31}');
console.log(dados.nome); // Rafael

// Stringify: objeto → string JSON
const json = JSON.stringify({ nome: "Rafael", ativo: true });
// '{"nome":"Rafael","ativo":true}'

// Com indentação (legível para debug)
console.log(JSON.stringify(dados, null, 2));

Em Python:

import json

# Parse
dados = json.loads('{"nome": "Rafael", "idade": 31}')
print(dados["nome"])  # Rafael

# Serialize
texto = json.dumps({"nome": "Rafael", "ativo": True})

Em Go:

import "encoding/json"

type Usuario struct {
    Nome  string `json:"nome"`
    Idade int    `json:"idade"`
}

var u Usuario
json.Unmarshal([]byte(`{"nome":"Rafael","idade":31}`), &u)

O padrão é o mesmo em todas as linguagens: uma função de parse (entrada: string, saída: estrutura nativa) e uma função de serialização (entrada: estrutura nativa, saída: string).

Erros comuns que quebram o parse

JSON é estrito. Um erro e o parse falha completamente:

// INVÁLIDO — vírgula depois do último campo
{
  "nome": "Rafael",
  "idade": 31,
}

// INVÁLIDO — aspas simples
{
  'nome': 'Rafael'
}

// INVÁLIDO — comentário (JSON não tem comentários)
{
  "nome": "Rafael" // usuário principal
}

// INVÁLIDO — chave sem aspas
{
  nome: "Rafael"
}

Esses quatro são os mais comuns. Todos aparecem frequentemente em JSON escrito manualmente — especialmente o trailing comma, porque todo editor moderno de código aceita isso como JavaScript válido, mas JSON não perdoa.

Quando recebo um JSON quebrado de uma API externa ou de um sistema legado, uso o JSON Formatter para identificar o erro exato e o número da linha — o parser nativo só diz "unexpected token", o que não ajuda muito quando o JSON tem 300 linhas.

JSON vs outras alternativas

XML: mais verboso, mais difícil de ler, suporta comentários e namespaces. Ainda dominante em sistemas SOAP e integrações corporativas antigas. Se você não tem escolha, tudo bem — mas se puder, JSON é mais simples.

YAML: mais legível para humanos (sem chaves), suporta comentários, bom para configuração. O problema é a especificação complicada cheia de casos-borda — YAML tem um histórico de vulnerabilidades de deserialização e comportamentos surpreendentes (o famoso país: NO que vira false porque NO é booleano em YAML). Ótimo para arquivos que humanos editam (Docker Compose, GitHub Actions), péssimo para troca de dados entre sistemas.

CSV: simples e pequeno para dados tabulares. Zero suporte para tipos ou estruturas aninhadas. Quando o dado é uma tabela plana, CSV ainda faz sentido. Quando tem hierarquia, não funciona.

Protocol Buffers / MessagePack: binários, muito mais eficientes em tamanho e velocidade de parse. Fazem sentido quando a performance importa mais que a legibilidade. Requerem schema.

JSON é o ponto médio: legível, sem schema obrigatório, suportado em todo lugar. Não é o mais eficiente, não é o mais expressivo — é o mais prático.

Perguntas frequentes

JSON aceita comentários?

Não. A especificação oficial não inclui comentários. Isso incomoda especialmente em arquivos de configuração, onde comentários seriam úteis. O tsconfig.json do TypeScript usa uma extensão chamada JSONC (JSON with Comments) que permite // e /* */, mas isso não é JSON padrão — parsers comuns rejeitam.

Se você precisa de comentários em arquivos de config, considere TOML ou YAML. Se for uma API, documente fora do payload.

Dá para ter número inteiro e decimal no mesmo campo?

Em JSON não existe distinção entre 42 e 42.0 — ambos são number. A distinção existe na linguagem que faz o parse: JavaScript vai ler como number, Go pode mapear para int ou float64 dependendo do tipo do campo na struct. O JSON em si não diferencia.

Um cuidado prático: inteiros muito grandes (acima de 2⁵³ em JavaScript) perdem precisão quando parseados como number. Para IDs grandes ou timestamps em milissegundos, é comum receber o número como string no JSON justamente para evitar esse problema.

JSON suporta dados binários como imagens?

Não diretamente. Se precisar incluir dados binários em JSON, o padrão é codificar em Base64 e incluir como string. A penalidade é +33% de tamanho e o custo de codificação/decodificação. Para arquivos grandes, normalmente faz mais sentido fazer um upload separado e incluir só a URL no JSON.

Qual a diferença entre null e campo ausente?

Em JSON são coisas distintas. { "preco": null } significa que o campo existe e seu valor é explicitamente nulo. Um objeto sem o campo preco significa que a informação não foi fornecida. Para APIs, a semântica importa: um PATCH com "preco": null pode significar "remover o valor", enquanto omitir o campo pode significar "não alterar". Documente o que sua API espera.

JSON é simples, mas imprecisão mata

O formato em si tem menos de dez regras. O que complica é o que não está no formato: sem schema, sem tipos além dos seis básicos, sem versionamento. Dois sistemas podem trocar JSON perfeitamente e ainda ter comportamentos diferentes por uma diferença em como cada lado interpreta um null ou um número com casas decimais.

Para dados simples entre sistemas controlados, JSON funciona bem sem nenhuma estrutura adicional. Para APIs públicas, contratos internos entre times, ou dados financeiros, vale a pena definir um schema — JSON Schema é o padrão para isso, mas isso é assunto para outro post.

RD
Author
Rafael Duarte
Desenvolvedor backend com passagem por fintech e SaaS B2B — trabalhou em times que escalaram APIs de zero a milhões de requisições. Carrega cicatrizes de produção suficientes para ter opiniões fortes sobre ferramentas, padrões e decisões de arquitetura. Não é acadêmico: leu a RFC do UUID quando precisou escolher entre v4 e v7 para uma tabela de alta escrita.
View profile