JSON

JSON vs Objeto JavaScript – Qual a diferença?

Olá, Web Developers!

Há algum tempo eu escrevi um post onde eu chamei um objeto de JSON, e um leitor me corrigiu. Ele estava completamente certo!

Muitas pessoas (inclusive eu) possuem a mania de chamar qualquer objeto JavaScript de JSON e muitas acreditam que são a mesma coisa. Isso está errado e eu notei que há muitas pessoas perguntando essa diferença, inclusive em grupos do Facebook e no StackOverflow.

Qual a diferença entre um Objeto Literal e o JSON?

Muitos sabem que o nome JSON vem de “JavaScript Object Notation”. Então, por que objetos JavaScript escritos de forma literal nem sempre são JSON?

{
   "a": 2,
   "b": 3
}

O exemplo acima pode ser considerado tanto um objeto literal em JavaScript quanto um JSON. Acontece que o JSON é um formato usado para a transferência de dados, independente de linguagem de programação, assim como o XML, CSV ou YAML.

Apesar da sintaxe de um objeto literal e do JSON serem muito parecidas (a ponto de podermos usar um JSON como objeto literal), o JSON possui especificações. Se sairmos dessas especificações, não estamos mais falando de um JSON.

Principais Diferenças entre JSON e Objeto Literal JavaScript

Chaves – As chaves no JSON devem vir entre aspas duplas. No Objeto Literal, as chaves podem ser strings com aspas simples, duplas, sem aspas, variáveis ou Symbols.

Valores – O Objeto Literal JavaScript aceita qualquer tipo de dado presente na linguagem (como Date) e até funções.

O JSON só aceita os seguintes tipos de valor:

  • string
  • number
  • boolean
  • null
  • array
  • outro JSON

Por essas limitações que o MongoDB usa o chamado BSON ao invés do JSON para armazenar dados. Além de armazenar o JSON em um formato binário, também adiciona suporte a outros tipos de dados, como:

  • integer
  • double
  • date
  • byte array
  • objeto BSON
  • array BSON
  • código JavaScript
  • dados binários em MD5
  • expressões regulares

Finalizando

Então, quando estamos transferindo dados, estamos falando de JSON, um formato de transferência de dados. Quando o JSON é interpretado por uma linguagem de programação, ele é convertido para um objeto (pode ser C#, Ruby(hash), Python(dictionary), Java, etc). Mesmo que no JavaScript a sintaxe de um objeto literal seja igual, ele não é um JSON.

Validando documentos JSON no PHP com JSON Schema

JSON Schema é uma especificação para validação de documentos JSON. A ideia é parecida com a de um XSD (XML Schema Definition) e um exemplo sólido da utilização de esquemas XML se dá na implementação e geração de notas fiscais eletrônicas, onde é muito importante que os dados estejam corretos e que se siga uma estrutura previamente definida.

Um esquema descreve a estrutura e os requerimentos que um documento deve ter. E a partir desses requerimentos podemos:

  • Gerar uma documentação do documento;
  • Validar o documento em cima do esquema;

É muito comum arquivos de configuração no formato JSON e com JSON Schema podemos validá-los. São muitos os casos de uso. Até mesmo quando a sua aplicação precisa, por algum motivo, consumir algum JSON de metadados relevantes para ela.

A especificação JSON Schema independe de linguagem. Você deve conseguir encontrar implementações dela para a sua linguagem favorita.

Para esse artigo, vou usar o PHP. Mas as ideias aqui são facilmente portadas para qualquer outra linguagem. Só vai mudar a implementação do código que lidará com a validação.

Suponhamos que a nossa aplicação precise consumir esse JSON:

{
  "name": "PHP",
  "frameworks": [
    "Laravel",
    "Symfony",
    "Zend Framework",
    "Slim"
  ]
}

Podemos validá-lo com o seguinte esquema:

{
  "type": "object",
  "properties": {
    "name": {
      "type": "string"
    },
    "frameworks": {
      "type": "array",
      "items": {
        "type": "string",
        "minLength": 3
      }
    }
  }
}

Ele define que o documento precisa ter um objeto com dois atributos: nome e frameworks. O atributo nome deve aceitar apenas string e o atributo frameworks deve aceitar um array, sendo que cada item dele deve ser do tipo string e não pode ter menos que dois caracteres.

Podemos testar a validação do nosso documento através do JSON Schema Validator:

Na primeira coluna coloca-se o esquema e na segunda o JSON a ser validado.

Faça um teste, adicione um item “Yi” no array do atributo frameworks:

{
  "name": "PHP",
  "frameworks": [
    "Laravel",
    "Symfony",
    "Zend Framework",
    "Slim",
    "Yi"
  ]
}

Não passou na validação por causa da restrição "minLength": 3 que especifica que os itens do array precisam ter pelo menos três caracteres.

Apesar do nosso exemplo ser simples e didático, ele nos dá uma visão geral do que pode ser feito. A especificação completa do JSON Schema você pode encontrar aqui.

Um exemplo um pouco mais complexo, retirado do Understanding JSON Schema que demonstra como podemos reaproveitar definições:

{
  "shipping_address": {
    "street_address": "1600 Pennsylvania Avenue NW",
    "city": "Washington",
    "state": "DC"
  },
  "billing_address": {
    "street_address": "1st Street SE",
    "city": "Washington",
    "state": "DC"
  }
}

O esquema:

{
  "$schema": "http://json-schema.org/draft-04/schema#",

  "definitions": {
    "address": {
      "type": "object",
      "properties": {
        "street_address": {
          "type": "string"
        },
        "city": {
          "type": "string"
        },
        "state": {
          "type": "string"
        }
      },
      "required": [
        "street_address",
        "city",
        "state"
      ]
    }
  },

  "type": "object",
  "properties": {
    "billing_address": {
      "$ref": "#/definitions/address"
    },
    "shipping_address": {
      "$ref": "#/definitions/address"
    }
  }
}

Observe que na definição dos atributos do objeto ao invés de duplicarmos as especificações nós as reutilizamos informando a referência de onde podem ser encontradas:

  "properties": {
    "billing_address": {
      "$ref": "#/definitions/address"
    },
    "shipping_address": {
      "$ref": "#/definitions/address"
    }
  }

Veja também que na definição de address as propriedades foram marcadas como required (obrigatórias):

"required": [
    "street_address",
    "city",
    "state"
]

Por exemplo, se o documento não informar um valor para a propriedade city ele não terá sucesso na validação.

Validando JSON Schema no PHP

Agora que tivemos um overview do que é e o que podemos fazer, chegamos na parte que realmente “toca” esse artigo que é a validação desses esquemas no PHP.

Temos duas formas de fazer isso:

  • Via arquivo físico de esquema, por exemplo, my_schema.json;
  • Em runtime via uma construção de arrays;

Essa segunda opção pode ser útil quando há a necessidade de alterar o esquema em tempo de execução. É possível criar um esquema dinâmico que responda à necessidades específicas.

E o documento JSON a ser validado temos a mesma relação. Ele pode ser importado de um arquivo físico ou ele pode ser construído em tempo de execução.

Utilizaremos a library justinrainbow/json-schema.


Observação: Daqui pra frente é necessário que você tenha conhecimentos básicos em PHP e na utilização do Composer, o gerenciador de dependências oficial do PHP.

Quer elevar os seus conhecimentos em PHP para um patamar profissional? Temos três excelentes cursos bases que podem te levar do zero ao mercado de trabalho:


Dando continuidade, no seu ambiente, onde normalmente você cria os seus projetos, crie uma nova pasta. No meu caso, vou chamá-la de json-schema. Dentro dessa pasta, crie um arquivo chamado composer.json com a seguinte definição:

{
    "require": {
        "justinrainbow/json-schema": "^5.2"
    }
}

Especificamos a dependência do nosso projeto. Ainda na raiz dele, crie um arquivo json chamado “curso-schema.json” com a seguinte definição:

{
  "type": "object",
  "properties": {
    "name": {
      "type": "string"
    },
    "frameworks": {
      "type": "array",
      "items": {
        "type": "string",
        "minLength": 3
      }
    }
  }
}

Crie outro arquivo chamado curso.json:

{
  "name": "PHP",
  "frameworks": [
    "Laravel",
    "Symfony",
    "Zend Framework",
    "Slim"
  ]
}

Agora, crie um arquivo PHP chamado validate.php. No momento essa é a estrutura do nosso projeto:

O validate.php deve ter a seguinte implementação:

<?php

require("./vendor/autoload.php");

use JsonSchema\Validator;

$data = json_decode(file_get_contents('curso.json'));
$schema = json_decode(file_get_contents('curso-schema.json'));

$validator = new Validator();
$validator->validate($data, $schema);

if ($validator->isValid()) {
    echo "O documento informado é válido.";
} else {
    echo "O documento é inválido. Violações: <br>";
    echo "<ul>";
    foreach ($validator->getErrors() as $error) {
        echo "<li>" . sprintf("[%s] %s\n", $error['property'], $error['message']) . "</li>";
    }
    echo "</ul>";
}

Para testá-lo, podemos usar o próprio servidor embutido do PHP. É só você navegar até a pasta desse projeto (via CMD ou terminal) e executar o seguinte comando:

php -S localhost:8000

E então executar o exemplo: http://localhost:8000/validate.php

Teste alterar o curso.json e colocar um nome inválido de framework para a nossa especificação, como “Yi”:

Além de importar um arquivo físico, também é possível construir as definições do esquema em tempo de execução, como mostra o exemplo na documentação:

$validator->validate(
    $request, (object) [
    "type"=>"object",
        "properties"=>(object)[
            "processRefund"=>(object)[
                "type"=>"boolean"
            ],
            "refundAmount"=>(object)[
                "type"=>"number"
            ]
        ]
    ],
    Constraint::CHECK_MODE_COERCE_TYPES
);

As possibilidades são muitas. Mais que importante que validar é conhecer melhor a especificação e tudo o que ela pode oferecer.

Um abraço!

REST não é simplesmente retornar JSON: indo além com APIs REST

É até comum, de certa forma, ouvirmos alguém falar que construiu uma API REST porque acabou disponibilizando um endpoint que retorna alguma informação no formato JSON. Mas isso, infelizmente, é um equívoco. Criar uma API REST nada tem a ver com simplesmente retornar algum JSON.

Neste post, vamos discutir sobre os conceitos de REST e JSON e verificar que, apesar de serem conceitos muito íntimos hoje, tecnicamente um não não tem nada a ver com o outro.

Mas, afinal de contas, o que é REST?


Hmmm, pelo jeito é algo arquitetural…

REST é um acrônimo para REpresentational State Transfer, ou seja, Transferência de Representação de Estado. O REST é, no final das contas, um estilo arquitetural que podemos utilizar ou não em nossas aplicações.

O conceito do REST foi criado pelo norte-americano Roy Fielding. Roy é também um dos principais responsáveis pela especificação técnica do protocolo HTTP. Sim, esse mesmo protocolo que você está utilizando nesse exato momento para visualizar esta página em nosso blog. A idéia do REST é utilizar de maneira mais eficiente e em sua plenitude as características do protocolo HTTP, principalmente no que diz respeito à semântica do protocolo. O resultado disso ao final das contas é, além da utilização mais “correta” do protocolo, um trânsito de informações mais eficiente e, por consequência, mais rápido.

Mas quais são as características do protocolo HTTP?

O protocolo HTTP, por decorrência de sua arquitetura, possui algumas características bem marcantes:

  • É um protocolo cliente-servidor: o protocolo HTTP se caracteriza por uma conexão feita entre uma máquina cliente e uma máquina servidora. Quando você acessa o nosso blog, por exemplo, você está fechando uma via de comunicação entre a sua máquina com o nosso servidor. É através dessa conexão que seu browser baixa o HTML, o CSS, o JavaScript e as imagens necessárias para renderizar a página solicitada;

  • A comunicação entre o cliente e o servidor é feita através de “mensagens HTTP”: o tráfego de dados entre um cliente e um servidor é feito através de porções de informação chamadas mensagens. Em uma “rodada” de comunicação, nós temos duas mensagens envolvidas: a mensagem enviada pelo cliente solicitando algo, chamada de request; e a resposta do servidor para a solicitação realizada, chamada de response. Estes dois componentes são essenciais para que a comunicação ocorra seguindo o protocolo HTTP e não é possível ter um request sem que depois haja um response e vice-versa;

  • O protocolo HTTP por definição não é “keep alive”: por padrão, uma conexão HTTP só dura até o momento em que o ciclo request-response é concluído. Logo após este ciclo, a conexão é automaticamente encerrada, ou seja: a conexão morre. Caso algum novo conteúdo precise ser trafegado entre o cliente e o servidor, uma nova conexão é aberta. Hoje, até existe maneiras de se modificar esse comportamento utilizando-se algumas flags na requisição (uma destas flags se chama justamente keep-alive), mas é importante destacar que o protocolo originalmente não foi planejado para essa finalidade;

  • O protocolo HTTP é utilizado de maneira assíncrona na maioria dos clientes: requisições HTTP são assíncronas por definição do lado dos clientes. Isso quer dizer que, se você precisa disparar duas requisições para baixar dois conteúdos distintos, o cliente pode disparar essas requisições ao mesmo tempo, sendo que cada uma delas pode ser respondida em um tempo diferente. O protocolo HTTP foi concebido para funcionar desta forma. Inclusive, quando você renderiza uma página, você pode verificar este comportamento observando a aba “Network” do Web Inspector se você utiliza browsers baseados no WebKit/Blink, como o Chrome:

Na figura acima, temos a inspeção do carregamento da página inicial do nosso blog. Cada um dos componentes listados abaixo do gráfico representa um componente que foi solicitado ao servidor, ou seja: houve um ciclo de requisição HTTP para a obtenção de cada um daqueles componentes, sendo que cada ciclo deste foi transmitido dentro de uma conexão própria ao servidor. O gráfico acima mostra o momento que a requisição foi disparada, bem como quanto tempo o servidor demorou para devolver a response correspondente.

Veja que no gráfico acima, podemos notar que o browser dispara várias requisições ao mesmo tempo, sendo que cada uma tem sua resposta em seu devido tempo. Isso prova que o protocolo HTTP é tratado de maneira assíncrona. Esse processo, inclusive, é chamado de pipelining.

Se você já lidou com AJAX por exemplo, já deve ter ouvido falar sobre o termo callback. Nós precisamos apelar para callbacks (ou promisses ou observables) justamente por causa desta característica do protocolo HTTP: nós precisamos de uma resposta do servidor, mas, pelo cliente fazer a requisição de maneira assíncrona, nós não sabemos exatamente quando essa resposta vai chegar… Por isso criamos callbacks (ou promisses ou observables) para serem executados quando o ciclo request-response for finalmente concluído.

  • As conexões no protocolo HTTP são independentes: como as conexões são abertas e fechadas a medida que algum conteúdo precisa ser trafegado, as conexões acabam sendo independentes umas das outras. Junto à característica assíncrona do protocolo HTTP, isso torna tecnicamente inviável que uma conexão possa “se comunicar” com alguma outra que esteja em curso, ou mesmo conhecer quais outros ciclos request-response estão em curso em determinado momento;

  • O protocolo HTTP é “stateless”: por decorrência dos três últimos pontos, nós afirmamos que o protocolo HTTP é stateless, ou seja, ele não guarda estado das requisições. Mais uma vez, isso é inviável, já que as conexões HTTP são independentes, assíncronas e, principalmente, por não serem keep alive. Se a conexão é imediatamente fechada após sua utilização, como podemos guardar alguma informação sobre ela? É exatamente por essa característica do protocolo HTTP que acabamos utilizando técnicas (como os cookies) para tentar guardar alguma informação necessária, como o usuário que está logado em uma aplicação por exemplo.

  • O protocolo HTTP é semântico: os recursos que podem ser disponibilizados por um servidor HTTP (como um página, por exemplo) podem ser acessados através de URIs (Unique Resource Identifier), que podem ser “traduzidas” para URLs (Unique Resource Locator). O grande ponto é que um servidor Web pode disponibilizar não somente páginas, ele também pode, por exemplo, fazer um upload de um arquivo. Para traduzir o que deve ser feito no servidor, o protocolo HTTP disponibiliza algo que nós chamamos de verbo ou método HTTP. A idéia é que esse verbo, associado ao request, indique o que deve ser feito no servidor.

Nós temos vários verbos HTTP, mas os principais, de maneira sucinta, são:

1) GET: indica que um recurso será recuperado do servidor. Por exemplo, quando você solicita uma página pelo seu browser;

2) POST: indica que um recurso será inserido ou criado no servidor. Um upload de um novo arquivo, por exemplo;

3) PUT: indica que um recurso será atualizado no servidor. Seria equivalente a um update em uma base de dados;

4) DELETE: indica que um recurso será removido do servidor. Seria o equivalente a um delete em uma base de dados.

Isso quer dizer que nós podemos invocar uma mesma URL (ou URI) em uma requisição HTTP, porém, dependendo da atribuição do verbo HTTP, a requisição irá desempenhar uma tarefa diferente no servidor. O verbo HTTP acaba determinando a semântica – ou significado/intenção – da requisição HTTP.

E o JSON? Onde ele entra na jogada?

O JSON (JavaScript Object Notation) não é um protocolo de transporte de informações como o HTTP. Ele é somente uma forma bem leve de representação e troca de informações. Ele tem a única função de levar informações de um lado para o outro. Nós podemos utilizar o JSON para transportar informações entre mensagens HTTP.

JSON x XML


Mas calma! A “treta” não precisa começar, rs

O XML também é uma forma de representação de informações. Porém, é uma forma mais “pesada” e verbosa de representação, já que preza pela “legibilidade” das informações a serem representadas.

Veja, por exemplo, um fragmento de um XML:

<clientes>
    <cliente>
        <id>1</id>
        <nome>TreinaWeb Cursos</nome>
        <idade>10</idade>
    </cliente>
</clientes>

A mesma informação acima poderia ser representada facilmente com o JSON abaixo:

"clientes" : [
    {
        "id" : 1,
        "nome" : "TreinaWeb Cursos",
        "idade" : 10
    }
]

Veja que, apesar de não ser tão explícita, a forma de representação com o JSON é muito mais direta e simples do que através do XML. Perceba também a quantidade de caracteres utilizados em cada uma das representações… Isso é um ponto muito importante! Como o JSON utiliza menos caracteres que o XML, ele também vai ocupar menos bytes dentro de um response com relação ao XML e, por consequência, o download de um response que contenha dados no formato JSON será mais rápido do que um response com as mesmas informações no formato XML. Essa é uma das principais justificativas para os desenvolvedores preferirem utilizar JSON do que XML para o intercâmbio de informações.

Então, o REST e o JSON possuem responsabilidades completamente diferentes!?


Me desculpa se isso foi um balde de água fria… 🙁

Sim, exatamente esse é o ponto! REST é um conceito arquitetural muito complexo, mas que no fim visa tirar vantagem de todas as características do protocolo HTTP, que é um protocolo de transporte. O JSON é somente uma forma de representar informações que precisam ser transportadas de um lado para outro. Sendo assim, podemos utilizar o protocolo HTTP para fazer o transporte de dados entre um cliente e um servidor.

Para conseguir utilizar o protocolo HTTP da forma correta, nós podemos adotar uma arquitetura baseada no REST. Agora, para fazer a representação das informações que precisam ser transportadas através do protocolo HTTP em uma arquitetura REST, nós podemos utilizar o JSON.

Mas então, eu posso ter uma API REST que responde XML?


Isso pode ser interessante…

Absolutamente, sim! Você, neste caso, só estará alterando a forma como as informações serão representadas nas requisições HTTP. Lembre-se: as responsabilidades do HTTP, do REST, do JSON e do XML são completamente diferentes. Isso, inclusive, é um trunfo da arquitetura REST: a representação das informações e o modo de transporte destas são completamente desacopladas.

Inclusive, é muito comum que APIs aceitem dados tanto no formato XML quanto no formato JSON, além de também responderem nestes dois formatos. As linguagens modernas hoje praticamente oferecem suporte nativo ao formato JSON, o que faz com que a adoção deste seja mais popular. Mas muitos sistemas, principalmente os sistemas legados, ainda são fundamentados no formato XML. Por isso é interessante que as APIs respondam nos dois formatos. Inclusive, as APIs definem a forma como vão fazer a leitura das informações com base no formato com que estas estão representadas, bem como definem o formato de dados a ser utilizado para a resposta, em uma etapa chamada content negociation.

“Perceba a petulância do protocolo HTTP!”


Do clássico meme “Percebe, Ivair, a petulância do cavalo!”

E ele é petulante com muita razão, haha. Afinal, toda a web hoje é fundamentada nele. Qualquer transporte de informação que for necessário entre aplicações hoje em dia passará pelo HTTP. Perceba como as características dele justificam muitas coisas que nós sem querer fazemos no automático quando estamos desenvolvendo soluções baseadas na Web.

Eu costumo dizer que entender os princípios básicos do protocolo HTTP é importantíssimo para qualquer desenvolvedor Web hoje em dia. Quando o desenvolvedor sabe como que as coisas “funcionam por baixo dos panos”, ele se preocupa mais com a maneira como ele vai desenvolvedor, além de entender bem melhor o porquê de algumas coisas serem do jeito que são.

Agora, deixa eu aproveitar o momento para fazer um “jabá”, hahaha: sabia que temos aqui no TreinaWeb um curso sobre o protocolo HTTP? Se você se interessar:

JUNTE-SE A MAIS DE 150.000 PROGRAMADORES