RESTful Web Services
Web Services é uma forma de comunicação entre dispositivos através da uma rede. Existem diversos padrões de comunicação que utilizam várias tecnologias e outros padrões já existentes na Web para fazer tal comunicação entre processos. Atualmente uma dos padrões mais populares é o Representational State Transfer (REST) que, em linhas gerais, define que a comunicação utiliza o HTTP como transporte das chamadas remotas, uma convenção sobre as URIs, além de não preservar estado entre as transações/requisições. Existe uma infinidade de Web Services que utilizam essa padronização para disponibilizar dados e serviços tais como o Flickr, Facebook, Google Maps, Google+, IMDB, What’s for Dinner, Yahoo Weather entre diversos outros. A maioria das aplicações atuais utilizam esses e outros serviços como extensões da aplicação para que essas informações fiquem conectadas e seja mais fácil compartilhar e consumir dados. Efeitos da Web 2.0.
O conjunto de requisições, buscas, consultas e operações que podemos executar, definem a API REST do serviço web. Esses serviços disponibilizam alguma documentação sobre quais operações estão definidas e que tipos de dados devem ser utilizados. Em geral, essas transações utilizam XML ou Javascript Object Notation (ou JSON) para fazer representar os dados a serem transmitidos.
JSON
O JSON nada mais é do que uma forma de representar informações semi estruturadas, podendo ser aplicado como substituto do XML em qualquer aplicação. A grande vantagem do JSON é consumir menos espaço, por ser menos verboso, que o XML além da maior facilidade de manipulá-lo já que se parecem com estruturas de várias linguagens além do próprio Javascript, como por exemplo Python e Ruby. Por isso é mais vantajoso onde há a necessidade de reduzir o tamanho da representação, como por exemplo na serialização de informações estruturadas em aplicações web. Além disso, muitas pessoas consideram o JSON mais legível que o XML. É exatamente nesse cenário que o JSON tem ganhado popularidade. É pouco conhecido, que o JavascriptCore – engine responsável por executar o Javascript presente no QML – já tem um parser e serializador de objetos JSON, tornando o seu uso ainda mais natural em aplicações QML.
AJAX
Outro recurso extensivamente utilizada nas páginas web modernas, é a comunicação assíncrona com o servidor através do Javascript. Essa técnica é popularmente chamada de Asynchronous Javascipt and XML (AJAX), que apesar de levar XML no nome continua sendo utilizada para descrever requisições assíncronas ao servidor mesmo não utilizando XML como camada de apresentação dos dados. A grande vantagem do AJAX é permitir que o browser execute outras atividades enquanto uma dada requisição é feita ao servidor, que toma preciosos milisegundos apenas esperando a resposta da requisição. O JavascriptCore implementa um tipo chamado XmlHttpRequest que é utilizado para fazer as requisições AJAX. Quando a resposta do servidor chega ao browser, uma função de callback é chamada (setada através da propriedade onreadystatechange de um objeto XmlHttpRequest) e executa a rotina que vai lidar com a resposta do servidor. Uma callback é uma função que será chamada quando uma dada ação ocorrer. Na web você pode encontrar várias implementações de referência de chamadas AJAX além de abstrações de diversos frameworks Javascript. No nosso caso vamos criar nossa própria abstração utilizando apenas o XmlHttpRequest. A função getHttpJson receberá uma URL do recurso a ser requisitado (através do método GET do HTTP) e uma callback a ser executada quando houver uma resposta:
function getHttpJson(request_url, callback)
{
// Criação do XmlHttpRequest para realizar a requisição AJAX
var request = new XMLHttpRequest();
// O seguintes parâmetros recebem respectivamente:
// 1 - Método HTTP a ser realizado
// 2 - URL requisitada
// 3 - Define se a chamada será executada assíncronamente
request.open("GET", request_url, true);
// Callback da requsição AJAX
request.onreadystatechange = function () {
// A callback 'onreadystatechange' sempre é chamado a qualquer atualização do status da requisição
// O valor 4 do readyState simboliza que a requisição foi fializada
// O status simboliza o status retornado no cabeçalho de resposta do HTTP, onde o valor 200 simboliza sucesso
if (request.readyState == 4 && request.status == 200) {
// O objeto JSON faz parte da imlementação JavascriptCore
// O 'responseText' contém o conteúdo da resposta da requisição
var json = JSON.parse(request.responseText);
// Chamada à callback real que está sendo encapsulado pelo getHttpJson
callback(json);
}
}
// Caso exista alguma informação a ser enviada no corpo da requisição HTTP, ela deve ir como parâmetro do send
request.send();
}
Essa abstração nos permite passar uma URL e uma callback, que nos retornará um objeto do tipo Array do Javascript (com as informações do JSON) como parâmetro dessa callback. É importante ressaltar que para o caso básico de acesso de recursos essa função é suficiente, porém pode será necessário incrementar o código acima para poder lidar com requisições mais complexas, que por exemplo, chame uma outra callback caso a requisição falhe ou ainda utilizar os demais métodos do HTTP na API RESTful.
QML + !!
O famoso site de tirinhas XKCD por exemplo, oferece uma API web RESTful para ler as tirinhas publicadas no site. Essa API é muito simples se comparada a outras APIs mas já nos permite fazer um leitor de tirinhas. Na especificação, a url http://xkcd.com/303/info.0.json nos permite retornar informações sobre a tirinha com id “303″. Dessa forma podemos fazer um wrapper mais elegante para nossa aplicação. Como exempl, considere a seguinte função, que abstrai qual esquema de construção da URL está sendo utilizada e se foca apenas nos parametros necessários (o numero da tirinha) e a callback que vai lidar com a resposta:
function getXkcdComic(num, callback) {
getHttpJson("http://xkcd.com/" + num + "/info.0.json", callback);
}
Se formos inspecionar o objeto JSON retornado pela chamada podemos fazer da seguinte forma:
getXkcdComic(303, function(json) {
var responseText = JSON.stringify(json); // Reserializando para Json para fins de demontração
console.debug(responseText); // Imprimindo resposta no console de debug
});
obteremos a seguinte linha impressa no console de debug:
{"img": "http://imgs.xkcd.com/comics/woodpecker.png", "title": "Woodpecker", "month": "7", "num": 614, "link": "", "year": "2009", "news": "", "safe_title": "Woodpecker", "transcript": "[[A man with a beret and a woman are standing on a boardwalk, leaning on a handrail.]]\nMan: A woodpecker!\n<<Pop pop pop>>\nWoman: Yup.\n\n[[The woodpecker is banging its head against a tree.]]\nWoman: He hatched about this time last year.\n<<Pop pop pop pop>>\n\n[[The woman walks away. The man is still standing at the handrail.]]\n\nMan: ... woodpecker?\nMan: It's your birthday!\n\nMan: Did you know?\n\nMan: Did... did nobody tell you?\n\n[[The man stands, looking.]]\n\n[[The man walks away.]]\n\n[[There is a tree.]]\n\n[[The man approaches the tree with a present in a box, tied up with ribbon.]]\n\n[[The man sets the present down at the base of the tree and looks up.]]\n\n[[The man walks away.]]\n\n[[The present is sitting at the bottom of the tree.]]\n\n[[The woodpecker looks down at the present.]]\n\n[[The woodpecker sits on the present.]]\n\n[[The woodpecker pulls on the ribbon tying the present closed.]]\n\n((full width panel))\n[[The woodpecker is flying, with an electric drill dangling from its feet, held by the cord.]]\n\n{{Title text: If you don't have an extension cord I can get that too. Because we're friends! Right?}}", "alt": "If you don't have an extension cord I can get that too. Because we're friends! Right?", "day": "24"}
que por sua vez não é tão legível. Recomendo fortemente o uso de alguma ferramenta de visualização de objetos JSON tais como o Online JSON Viewer que ajudam a visualizar os dados e sua estrutura.
Com tais dados e funções utilitárias, fica fácil criar um leitor do XKCD que utiliza a API RESTful do XKCD. Recomendo agregar essas funções relativas a comunicação com o servidor em um arquivo Javascript separado para que a implementação fique distinta de seu uso no QML. Aqui vou chamar esse arquivo de “xkcd.js”. O seguinte código cria um leitor do XKCD bem simples e utiliza o “xkcd.js” com o alias XKCD, de modo que podemos chamar as funções definidas no arquivo Javascript através desse objeto.
import QtQuick 1.0
import "xkcd.js" as XKCD
Rectangle {
id: comicViewer
property int num // Número da tirinha
property url image // Imagem da tirinha
property string title // Título da tirinha
property string alt // Texto alternativo da tirinha (sarcasmo do XKCD)
width: 300
height: 300
color: "white"
// Retorna as informações do servidor toda vez que o numero do quadrinho
// é alterado
onNumChanged: {
XKCD.getXkcdComic(num, function (json) {
comicViewer.image = json.img;
comicViewer.title = json.title;
comicViewer.alt = json.alt;
});
}
// Troca o número da tirinha atual imediatamente após a incialização do
// componente atual
Component.onCompleted: comicViewer.num = 303;
// Imagem da tirinha
Image {
id: comicImage
anchors {
fill: parent
margins: 50
}
source: image
fillMode: Image.PreserveAspectFit
smooth: true
}
// Mostra o título sobre a tirinha
Text {
anchors {
horizontalCenter: comicImage.horizontalCenter
bottom: comicImage.top
}
text: title
font.pixelSize: 30
}
// Mostra o texto alternativo abaixo da tirinha
Text {
anchors {
top: comicImage.bottom
bottom: parent.bottom
left: parent.left
right: parent.right
}
text: alt
horizontalAlignment: Text.AlignHCenter
wrapMode: Text.WordWrap
}
// Área esquerda da tela quando clicada vai para a tirinha anterior
MouseArea {
anchors {
left: parent.left
right: parent.horizontalCenter
top: parent.top
bottom: parent.bottom
}
onClicked: num -= 1;
}
// Área direita da tela quando clicada vai para a próxima tirinha
MouseArea {
anchors {
right: parent.right
left: parent.horizontalCenter
top: parent.top
bottom: parent.bottom
}
onClicked: num += 1;
}
}
Para testar esse exemplo, basta salvá-lo como, por exemplo “xkcd.qml” e abrí-lo com qmlviewer ou carregar em uma QDeclarativeView..
No related posts.
RSS
2 comentários (read them below or adicionar um)
Obrigado por este exemplo. Esta metodologia REST é muito útil nas aplicações QML.
Não poderá ser possível também usar QML e um servidor com uma API REST sobre o protocolo HTTP para desenvolver sites? Isto é desenha-los em QML? Acho que seria um bom tema para estudar…
Na verdade não existe uma forma de transformar QML em HTML + CSS + Javascript (pelo menos ainda).
Discutimos um pouco sobre isso no post:
http://blog.qtlabs.org.br/2011/05/30/transformando-o-qml-no-proximo-flash/