QML + RESTful Web Services

Escrito por Daker Pinheiro em 7 de outubro de 2011

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..

Visualizador de tirinhas XKCD feito em QML

Visualizador de tirinhas do XKCD feito em QML

 

 

Gostou? Então compartilhe:

No related posts.


2 comentários  (read them below or adicionar um)

Rizó Isrof 9 de outubro de 2011 às 16:59
 

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…

Responder

Daker Pinheiro 14 de outubro de 2011 às 18:58
 

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/

Responder

Deixar um comentário

Artigo anterior:

Próximo artigo: