Saudações. Nesse artigo vamos aprender e explorar o formato de dados JSON. Todos os softwares, plataformas online e serviços digitais o utilizam, logo, somos forçados a aprende-lo para sobreviver.
1 – O que é JSON
JSON significa JavaScript Object Notation. É um formato de representação e armazenamento de dados, tanto para humanos (usuários) quanto para computadores (programas) criados na linguagem JavaScript e que se espalhou para todos as linguagens de programação, bancos de dados (JSONB) e aplicativos.
Você não precisa aprender nenhuma linguagem de programação para aprender JSON.
Ele foi concebido para ser simples, ter poucas regras e ser armazenado e transmitido em texto simples.
O bloco de código abaixo é um exemplo dos dados digitados por um usuário em um formulário online e enviado para um site:
{
"nome": "Patolino Silva",
"idade": 22,
"profissao": "vendedor",
"data_nascimento": "01/01/2013"
}
JSON é algo tão simples que se você entendeu o bloco acima, você ja sabe 98% do que precisa saber para trabalhar com ele!
Caso deseje aprender de forma mais ortodoxa, a RFC 4627 define todas as regras para uso de JSON:
2 – Tipos de dados
Informações digitais são armazenadas e processadas baseadas no seu tipo, os tipos básicos são:
- Números inteiros (integer): todos os números positivos ou negativos que são escritos apenas cos caracteres: 0 a 9 e hífen, não podem ser envolvidos por aspas. Exemplos:
- 0
- -14
- 83839283
- 42
- -1
- Números de ponto flutuante (float): todos os números que envolvem frações, porcentagem, números racionais em geral e são escritos com os caracteres 0 a 9, hífen e ponto. Usa-se o ponto no lugar da virgula como divisor. Exemplos:
- 3.14
- -14.5
- 42.708381922
- -1.1
- Texto (string): conjunto de caracteres de texto, ASCII e UNICODE, delimitados por aspas duplas. Números envolvidos por aspas serão tratados como se fossem texto, ou precisarão ser convertidos para inteiros no código que recebe o JSON. Exemplos:
- “O rato roeu a roupa do rei de roma”
- “0”
- “42”
- “42.12345”
- “pi=3.14”
- Valor booleano (boolean): representação de um bit, sendo bit 0 para false (desativado, ausente) ou bit 1 para true (ativado, verdadeiro). Valores admitidos somente em minúsculo (não use T ou F maiúsculo como no Python):
- true
- false
- Lista (array): é um conjunto de valores com posições numéricas sequenciais iniciando no índice zero. Uma lista é iniciada com o caracter “[” e finalizada com o caracter “]”, os itens são separados por vírgula. O primeiro elemento de uma lista está no índice 0, e se uma lista tem 100 elementos o último terá o índice 99. Exemplos:
- [ “O rato roeu a roupa do rei de roma”, 42, true, 3.14, “42.123456” ]
- [ “terror”, “suspense”, “comédia”, “documentario” ]
- []
- [ true, true, false, true, false, true, true ]
- [ 3.14, 2, 3, 5, 7, 9, 11, 13, 17, 19, 23 ]
- Objeto (object): é um conjunto de valores, semelhante à lista mas onde o índice possui um nome (nome da propriedade), que deve ser obrigatoriamente uma string. Um objeto é iniciado com o caracter “{” e finalizado com o caracter “}”. Os valores das propriedades podem ser de qualquer tipo, incluindo listas e outros objetos. Exemplos:
- { “nome”: “Patolino” }
- { “nome”: “Patolino”, “idade”: 22 }
- { “estados_atendidos”: [ “DF”, “MT”, “MS”, “GO” ] }
- { “pi”: 3.14, “raio”: 14938.4719, “altura”: 987 }
- { “cadastro”: { “nome”: “Patolino”, “idade”: 12 } }
- Tipo nulo – sem tipo e sem dados – null: quando uma propriedade não possui um tipo ele é tido como nulo e é representado pela palavra explicita null, sem aspas simples ou duplas. A presença de valores nulos é perigosa e deve ser evitada na declaração, ou mitigada no programa que recebe o dado nulo. Exemplos de JSON onde o null pode aparecer:
- { “nome”: null, “idade”: null }
- [ null, null, null, null ]
- { “cadastro”: { “nome”: “Patolino”, “idade”: null } }
Com os tipos básicos, podemos preencher quaisquer variáveis usando JavaScript e algum dos valores acima.
O texto do JSON recebido ou enviado entre softwares deve ser um objeto: listas [] ou objetos {}. Quem vai determinar se o objeto é inicialmente object {} ou array [] será o sistema ou software que você irá usar para a interação.
Registro exportado para lista:
[
1,
"Patolino Pio",
"2021-03-17",
"M"
]
Registro exportado para objeto:
{
"id": 1,
"nome": "Patolino Pio",
"nascimento": "2021-03-17",
"sexo": "M"
}
Observe que objetos {} são melhores para conservar o nome da propriedade que armazena o valor. Listas são melhores para transportar vários objetos (tabelas, veja a seguir).
Veremos as implicações dos tipos e como acessar os dados mais adiante.
3 – Tabelas
Tabelas são transportadas em listas ou objetos, observe a tabela abaixo:
id | nome | nascimento | sexo |
1 | Patolino Pio | 2021-03-17 | M |
2 | Pernalonga III | 2023-12-01 | M |
3 | Felícia Feliz | 2022-07-25 | F |
4 | Lilica Monte | 2024-07-09 | F |
Representação JSON em lista (array) de elementos contendo registros (object):
[
{ "id": 1, "nome": "Patolino Pio", "nascimento": "2021-03-17", "sexo": "M" },
{ "id": 2, "nome": "Pernalonga III", "nascimento": "2023-12-01", "sexo": "M" },
{ "id": 3, "nome": "Felícia Feliz", "nascimento": "2022-07-25", "sexo": "F" },
{ "id": 4, "nome": "Lilica Monte", "nascimento": "2024-07-09", "sexo": "F" }
]
Apresentação JSON mais expandida do mesmo texto acima:
[
{
"id": 1,
"nome": "Patolino Pio",
"nascimento": "2021-03-17",
"sexo": "M"
},
{
"id": 2,
"nome": "Pernalonga III",
"nascimento": "2023-12-01",
"sexo": "M"
},
{
"id": 3,
"nome": "Felícia Feliz",
"nascimento": "2022-07-25",
"sexo": "F"
},
{
"id": 4,
"nome": "Lilica Monte",
"nascimento": "2024-07-09",
"sexo": "F"
}
]
Listas podem conter objetos, e esses objetos conter listas, assim o JSON pode transportar banco de dados inteiros. Exemplo de um banco de dados contendo 3 tabelas (clientes, login, emails) exportada em JSON:
{
"clientes": [
{ "id": 1, "nome": "Francisco Silveira", "status": 1 },
{ "id": 2, "nome": "Amanda Beatriz", "status": 2 }
],
"login": [
{ "cliente_id": 1, "user": "francisco", "senha": "tulipa" },
{ "cliente_id": 2, "nome": "amanda", "senha": "petunia" }
],
"emails": [
{ "cliente_id": 1, "email": "francisco.sil@gmail.com", "use": true },
{ "cliente_id": 2, "email": "amanda2003@gmail.com", "use": true }
]
}
4 – Usando JSON em variáveis (JS)
O JSON tem como foco o acesso estruturado às informações, assim, saber o caminho de uma informação dentro de um documento JSON lhe permite acessar diretamente o que deseja. Vamos considerar uma variável “item” onde um JSON será armazenado:
let item = {
"clientes": [
{ "id": 1, "nome": "Francisco Silveira", "status": 1 },
{ "id": 2, "nome": "Amanda Beatriz", "status": 2 }
],
"usuarios": [
{ "cliente_id": 1, "user": "francisco", "senha": "tulipa" },
{ "cliente_id": 2, "nome": "amanda", "senha": "petunia" }
],
"emails": [
{ "cliente_id": 1, "email": "francisco.sil@gmail.com", "use": true },
{ "cliente_id": 2, "email": "amanda2003@gmail.com", "use": true }
]
}
console.log(item.clientes)
// Retorno: array list
// [
// { "id": 1, "nome": "Francisco Silveira", "status": 1 },
// { "id": 2, "nome": "Amanda Beatriz", "status": 2 }
// ]
console.log(item.clientes[0])
// Retorno: object
// { "id": 1, "nome": "Francisco Silveira", "status": 1 }
console.log(item.clientes[0].nome)
// Retorno: string
// "Francisco Silveira"
5 – JSON transportando caracteres multibyte
Estamos acostumados a representar texto usando a tabela ASCII (A a Z, 0 a 9, !@#$%ˆ&*(){}’”;:/?.>,<~`|\) e isso basta para a maioria dos casos.
O JSON é naturalmente concebido para transportar caracteres multibyte em UTF-8, o que envolve o uso de alguns códigos binários dentro do texto – um detalhe a ser tratado com cuidado.
Observe o retorno de uma tradução chinês para português transportada em JSON:
{
"input": "O rato roeu a roupa do rei de roma",
"output": "老鼠咬破了罗马国王的衣服"
}
Todos os softwares devem ter capacidade de interpretar UTF-8, que é o padrão multibyte do formato JSON, assim, sempre que enviar ou receber um JSON usando HTTP, cuide para que o cabeçalho “Content-Type” seja definido com o valor “application/json; charset=utf-8” ou “application/json; charset=utf-16“, em vez do trivial “application/json“. Todos os 3 valore são corretos mas o “UTF-8” é o padrão RFC.
Infelizmente pode acontecer de um JSON ser processador por um software sem essas capacidades, exemplos e casos comuns:
- Software travado em ISO: caracteres UTF serão convertidos de forma errada para ISO-8859 e corrompidos no processo, a palavra “comunicação” pode acabar se tornando “comunica
��
o“, nomes com acentos podem acabar corrompidos e gerando problemas na apresentação; - Softwares travando ao receber ou perceber conteúdo binário no texto;
- Editores de texto antigos ou mal programados podem corromper o conteúdo do JSON (um caracter UTF-8 no final da string mal interpretado resulta na remoção das aspas que encerravam a string, corrompendo sintaticamente todo o JSON);
Quando for possível enfrentar algum dos problemas acima, deve-se optar por representar as strings em codificações seguras para transporte em ASCII (texto simples). Exemplos de codificação:
{
"raw": "老鼠咬破了罗马国王的衣服",
"utf8": "老鼠咬破了罗马国王的衣服",
"unicodeEscape": "\u8001\u9f20\u54ac\u7834\u4e86\u7f85\u9a6c\u56fd\u738b\u7684\u8863\u670d",
"urlEncoded": "%E8%80%81%E9%BC%A0%E5%92%AC%E7%A0%B4%E4%BA%86%E7%BD%97%E9%A9%AC%E5%9B%BD%E7%8E%8B%E7%9A%84%E8%A1%A3%E6%9C%8D",
"base64": "6ICA6bKA5a2m5a6a5Y+v55Sf5Yqg5Y2B5bCG6K6k5L2/5a2m5a6a5Y+v"
}
O método base64 e unicodeEscape garantem que a string seja transportada no JSON e compatível com a tabela ASCII (formato universal). Embora não seja agradável esse tipo de gambiarra, ela pode servir para contornar problemas com unicode.
6 – JSON transportando binários
Quando se faz necessário transportar conteúdo 100% binário (bytes que vão variar entre o decimal 0 e 255, sem qualquer previsão de representação ASCII ou unicode), como é o caso de documentos (PDF, PPT, DOC, DOCX), imagens (JPEG/JPG, PNG, WEBP, GIF), áudio (WAV, MP3) e outros.
Não é possível colocar esse binário direto no JSON, ele obrigatoriamente precisará ser codificado. O base64 (RFC 4648) é o formato mais adequado para isso.
O texto base64 no mundo real pode ser grande e tornar o JSON enorme. Observe o exemplo abaixo onde crio um JSON com 3 documentos (anexos):
[
{
"filename": "cnh.pdf",
"mime-type": "application/pdf",
"content": "QmFzZSA2NCBkZSBleGVtcGxvIGFwZW5hcw=="
},
{
"filename": "rg.pdf",
"mime-type": "application/pdf",
"content": "T3V0cm8gYmFzZTY0IGRlIGV4ZW1wbG8="
},
{
"filename": "foto_rosto.png",
"mime-type": "image/png",
"content": "VGVyY2Vpcm8gYmFzZTY0IGRlIGV4ZW1wbG8="
},
]
Usando os mesmos dados, observe um método mais simples (padrão de base64 incorporado em tag HTML):
[
{
"filename": "cnh.pdf",
"content": "data:application/pdf;base64,QmFzZSA2NCBkZSBleGVtcGxvIGFwZW5hcw=="
},
{
"filename": "rg.pdf",
"content": "data:application/pdf;base64,T3V0cm8gYmFzZTY0IGRlIGV4ZW1wbG8="
},
{
"filename": "foto_rosto.png",
"content": "data:image/png;base64,VGVyY2Vpcm8gYmFzZTY0IGRlIGV4ZW1wbG8="
}
]
7 – Bizarrices do mundo real
Observe este documento JSON:
{
"tipo": "Cilindro",
"nome": "Caixa-dagua-principal",
"altura": "145",
"largura": "125",
"pi": "314",
"instalado": "Não"
}
O programa que o produziu considera que o receptor irá processá-lo com as seguintes regras:
- As propriedades “altura“, “largura” e “pi” são originalmente do tipo float, mas foram multiplicadas por 100 para serem convertidas em inteiro, e depois foram representadas no JSON como string;
- O receptor deve converter essas 3 propriedades acima para inteiro, depois para float dividindo por 100 para chegar ao número de ponto flutuante exato;
- A propriedade “instalado“, quando for “Não”, “Nao”, “nao”, “NÃO”, “No”, “NO” ele deverá ser convertido em false, caso contrario ele será considerado true;
Você se pergunta: “Por que alguem faria desse jeito?”. Não seria mais simples assim:
{
"tipo": "Cilindro",
"nome": "Caixa-dagua-principal",
"altura": 1.45,
"largura": 1.25,
"pi": 3.14,
"instalado": false
}
Obviamente o formato acima seria melhor e dentro das melhores práticas. Infelizmente exemplos assim são comuns e você deve ficar sempre atendo aos padrões do emissor e receptor dos dados para não enlouquecer.
Muitos programadores se cansam dos problemas causados ao lidar com o armazenamento binário dos pontos flutuantes e preferem usar inteiros, exemplo:
- Para dinheiro, armazenar a quantidade de centavos, usando 50 em vez de 0.5 (OpenPIX é um site que faz cobranças usando valores assim);
- Em um posto de gasolina, para cobrar por mililitros, 1 litro seria representado por 1000 ml, e multiplica pelo valor do ml em vez do valor do litro, arredondando para cima (você perde frações de centavo para o posto);
- Usar palavras “Ativado” ou “Desativado” em vez de true ou false pode ser uma forma preguiçosa de não converter os dados e apenas mostrar ao usuário na tela;
Fique atento e boa sorte.
Conclusão
JSON veio para ficar. Você deve possuir destreza e domínio completo dele para se destacar nesse novo mundo automatizado, integrado e guiado por Inteligência Artificial.
Espero que tenha ajudado, até mais!
Patrick Brandão, patrickbrandao@gmail.com