WebServices: XML vs JSON-RPC

RPC é a sigla de Remote Procedure Call, ou seja, “chamada a procedimento remoto”. A coisa funciona mais ou menos assim: De um lado temos um programa tentando fazer uma chamada a uma rotina que não se encontra na própria máquina, mas em outra, diferente. Do outro lado temos um conjunto de funções que podem ser executadas por alguém que têm “assinaturas” pré-definidas.

O lado do chamador “empacota” os parâmetros que vai usar na chamada da rotina remota, envia esse pacote para a outra máquina que desempacota a requisição, a interpreta e só então executa a função correta…. O ato de “empacotar” os parâmetros chama-se Marshalling e o de “desempacotar”, UnMarshalling.

WebServices, no modelo RPC tradicional, chamado SOAP (Simple Object Access Protocol, que de “simples” não tem nada, hoje em dia) usa XML (eXtenssible Markup Language) para publicar um conjunto de “interfaces” que o chamador pode usar. Esse XML é chamado de WSDL (Web Service Definition Language). O chamador usa essa informação para fazer o Marshalling de acordo com o que o “serviço” espera receber…

Se você já mexeu com XML e com Web Services sabe como é trabalhoso lidar com esses detalhes e, provavelmente, deixa isso a cargo de alguma biblioteca pré-empacotada. Especialmente porque os WSDL lidam com XSDs (XML Schema Definitions)… E a coisa só complica mais e mais…

Há tempos tenho observado um esquema de marshalling mais simples, usado especialmente com o AJAX (Assynchonous Javascript And XML). A turma do Javascript resolveu que um objeto pode ser “empacotado” sob forma de uma string simples… Um objeto pode ser empacotado entre os caracteres ‘{‘ e ‘}’, contendo os pares key:value de cada atributo ou membro de dados… Ainda, podemos ter arrays, delineados entre ‘[‘ e ‘]’. Cada “campo” é separado por ‘,’. O nome desse esquema de marshalling é JSON (JavaScript Ohject Notation) e é tremendamente mais simples de se trabalhar do que XML.

Ora, pra quê usar SOAP como RPC se podemos usar JSON? É muito mais simples e o empacotamento fica menor, trafegando mais rapidamente pelos fios… Tudo o que precisamos é de um padrão de marshalling pelo JSON… E ele existe: chama-se JSON-RPC. Funciona assim:

Suponha que você queira chamar uma função, no lado servidor, chamada “calc” e tenha que passar dois valores inteiros. Para isso você só precisa montar a requisição:

{"jsonrpc":"2.0", "method":"calc", "params":[3,4], "id":1}

O primeiro item diz que o JSON-RPC está sendo usado e a versão mais recente (publicada e padronizada) é a “2.0”. Em seguida temos o nome do método que será chamado. Depois, os parâmetros… Neste ponto vale observar que os parãmetros podem ser um número, uma string, um array ou um objeto JSON… E, por fim, um identificador da requisição, que pode ser um número, uma string ou null (sendo que null não deve ser usado, segundo a especificação).

Compare essa requisição com toda a necessidade de namespaces, schemas e a formatação esquisita do XML! É bem mais simples e menor!

Isso não significa que não se possa “embelezar” o pacote JSON:

{
  "jsonrpc":"2.0",
  "method":"calc",
  "params":[1,
            2],
  "id":1
}

Obtida a string JSON que forma a requisição, a enviamos junto com o protocolo HTTP (ou HTTPS):

GET myserver.com/service.py HTTP/1.1
Host: http://myserver.com/
Content-Type: application/json-rpc
Content-Length: 57

{"jsonrpc":"2.0", "method":"calc", "params":[3,4], "id":1}

Obs: O Content-Length está com 57 bytes porque o protocolo HTTP exige que o par “\r\n” termine a última string.

O processador exemplificado aqui como service.py (em Python!) vai simplesmente obter a linha passada por HTTP, e decodificá-la (pode até usar um Javascript para isso!). Depois de processar a chamada, vai reponder com outra linha JSON:

{"jsonrpc":"2.0", "result":7, "id":1}

Da mesma forma, “result” pode ser um número, uma string ou outro objeto JSON. O detalhe é que o “id” é o mesmo que mandamos na requisição, informando ao chamador que essa resposta é para ele (caso tenham sido feitas ‘n’ chamadas por chamadores diferentes no mesmo programa!).

Em caso de erro, a resposta é um pouquinho diferente. Por exemplo:

{"jsonrpc":"2.0", "error":{"code":-32600, "message":"Invalid Request"}, "id":1}

Isso ai vêm como resposta num bloco response do HTTP…

Existem alguns códigos de retorno padronizados e algumas respostas para circunstâncias específicas de erro (veja o padrão aqui).

Convenhamos: Criar um parser para JSON é extremamente mais simples do que um parser para XML… E JSON, pela sua característica, suporta a estrutura de árvore tão bem quanto XML… Ele facilita a nossa vida porque os dados só podem ser de um dos sete tipos:

  • Números Inteiros (long long);
  • Númeoros em ponto-flutuante (double);
  • true ou false;
  • Strings, delimitadas por ” e ” (aceitando sequências de escape no estilo de C);
  • Objetos JSON, delineados entre ‘{‘ e ‘}’;
  • Arrays, delineados por ‘[‘ e ‘]’;
  • null.

Suponha, por exemplo, que vocẽ queira receber como resposta o conteúdo de um arquivo… Basta codificá-lo em BASE-64 e colocá-lo dentro de uma string de um objeto JSON, por exemplo! Ou, melhor ainda, trafegar pedaços (chunks) de um arquivo em um objeto JSON, para não correr o risco de estourar a capacidade de alocação do webserver ou do cliente! As possibilidades são ilimitadas… e bem simples de implementar!!

Anúncios

Deixe um comentário

Faça o login usando um destes métodos para comentar:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s