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:
JSON
{ "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:
JSON
[ 1, "Patolino Pio", "2021-03-17", "M" ]Registro exportado para objeto:
JSON
{ "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):
JSON
[ { "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:
JSON
[ { "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:
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:
JavaScript
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:
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:
JSON
{ "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):
JSON
[ { "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):
JSON
[ { "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:
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:
JSON
{ "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