Tag Archives: web

YQL! Parte 3: Usando tabelas do YQL! em uma aplicação Ruby e Java com Restfulie

Nos dois posts anteriores foi explicado como desenvolver as tabelas do YQL!, inclusive escrevendo o código Javascript para tabelas que envolviam uma lógica mais complexa. Nesse post eu vou mostrar como é possível utilizar uma tabela já criada (usando como exemplo a tabela criada no post anterior) tanto em uma aplicação Ruby quanto em uma aplicação Java utilizando o Restfulie para acessar.

O que é o Restfulie?

O Restfulie é uma biblioteca que permite acessar serviços REST através de uma interface agradável. Além disso, os serviços REST podem possuir hypermedia em suas respostas e através da biblioteca é possível navegar sobre os links através da própria API.

Em Ruby com uma aplicação Rails

Considerando que você esteja utilizando RVM (e se não estiver, já está na hora) e com o Rails 3 configurado, adicione a gem do Restfulie ao seu Gemfile:

gem 'restfulie'

Em seguida, crie um novo controller para conseguirmos fazer uma tela para visualizar os resultados:

rails g controller cursos

No seu controller, adicione um método novo que fará a ação de buscar as informações da tabela do YQL! e disponibilizar essas informações para a View:

def index
  #vamos adicionar codigo aqui
end

No método index vamos declarar duas variáveis, uma para guardar a url do YQL! e outra para armazenar a query que vamos executar. Com isso teremos:

def index
  base_url = "http://query.yahooapis.com/v1/public/yql"
  query = "use 'http://ahalmeida.me/tabelas_yql/caelum.proximoscursos.xml'; select * from caelum.proximoscursos;"
  #vamos fazer a consulta aqui
end

O próximo passo é executarmos a consulta com o Restfulie. Para isso, basta adicionarmos o seguinte código:

Restfulie.at(base_url).get(:q => query)

O que o código acima faz é uma requisição get para a base_url passando um parâmetro q cujo valor é a query que desejamos executar. Podemos pegar a resposta desse método get e guardarmos em uma variável. Essa variável guardará uma estrutura de hashes que representa a mesma estrutura do XML devolvido pelo serviço. No caso, o XML devolvido pelo YQL! é algo similar com:

<query xmlns:yahoo="http://www.yahooapis.com/v1/base.rng"
    yahoo:count="1" yahoo:created="2010-10-19T12:51:13Z" yahoo:lang="en-US">
    <results>
        <cursos>
            <curso>
                <nome>FJ-26:
Laborat&oacute;rio Web com JSF2 e CDI</nome>
                <data>23/10 a 27/11</data>
                <periodo>S&aacute;bado (9:00 as 17:00)</periodo>
                <cidade>Rio de Janeiro</cidade>
                <comentario/>
            </curso>
            <!-- outros cursos aqui ... -->
        </cursos>
    </results>
</query>

Com isso o código para conseguirmos buscar todos os cursos com o Restfulie dessa estrutura de XML da resposta é:

resp = Restfulie.at(base_url).get(:q => query)
@cursos = resp['query']['results']['cursos']['curso']

Dessa forma a classe CursosController ficaria:

class CursosController < ApplicationController   
  def index
    base_url = "http://query.yahooapis.com/v1/public/yql"
    query = "use 'http://ahalmeida.me/tabelas_yql/caelum.proximoscursos.xml'; select * from caelum.proximoscursos;"  
    resp = Restfulie.at(base_url).get(:q => query)
    @cursos = resp['query']['results']['cursos']['curso']
  end
end

A variável cursos disponibilizada para a view é um Array contendo objetos que possuem as informações dos cursos devolvidas pelo YQL!. Para finalizar podemos criar uma view para o index do Controller que acabamos de fazer e mostrar as informações dos cursos:

<% @cursos.each do |c| %>
  <%= c.nome %>
  <%= c.periodo %>
<% end %>

Em Java

O processo em Java é similar. Através do Restfulie que está disponível em http://github.com/caelum/restfulie-java você consegue também consumir serviços REST, no entanto é necessário escrever um pouco mais de código do que na versão Ruby, por características da linguagem.

De qualquer maneira, uma vez que tenha baixado o Restfulie e configurado em seu projeto, vai ser necessário representar através de classes a estrutura do XML que será devolvido. No caso da query de cursos da Caelum teremos as seguintes classes:

@XStreamAlias("query")
public class Query {
    private Results results;
}

@XStreamAlias("results")
public class Results {
    private	Cursos cursos;
}

@XStreamAlias("cursos")
public class Cursos {
    @XStreamImplicit(itemFieldName="curso")
    private List cursos;
}

@XStreamAlias("curso")
public class Curso {
    private String nome;
    private String data;
    private String periodo;
    private String cidade;
    private String comentario;
}

Em seguida podemos criar uma instância do Restfulie e registrar os tipos que desejamos receber:

RestClient client = Restfulie.custom();
client.getMediaTypes().register(new XmlMediaType().withTypes(Query.class));

O próximo passo é executarmos a requisição e pegarmos o objeto que representa o XML e percorrermos todos os cursos:

Response response = client.at("http://query.yahooapis.com/v1/public/yql?q=use%20'http%3A%2F%2Fahalmeida.me%2Ftabelas_yql%2Fcaelum.proximoscursos.xml'%3B%20select%20*%20from%20caelum.proximoscursos%3B").accept("text/xml;charset=utf-8").get();

Query q = response.getResource();

for (Curso c : q.getResults().getCursos().getCursos()) {
    System.out.println(c.getNome());
}

Logicamente, esse código pode ser reaproveitado em qualquer tipo de aplicação (seja web ou Desktop).

Conclusão

Para utilizar uma tabela criada basta consumir essa tabela através de uma API que envie requisições HTTP. O ideal é que ela também torne agradável trabalhar com a resposta. Nesse caso utilizei o Restfulie, mas poderia ter sido também qualquer outra biblioteca, como o HTTParty.

Etiquetado , , , ,

YQL! Parte 2: Criando novas tabelas

Recapitulando

No primeiro post (leia aqui) eu falei sobre a busca de dados públicas na web e da utilização básica das tabelas do YQL! e a criação de queries através de tabelas já existentes dentro do próprio serviço (sejam do próprio Yahoo! ou desenvolvidas por outras pessoas).

E quando não existe uma tabela pronta?

Existem tabelas no YQL! para realizarmos diversas pesquisas sobre os mais variados tipos de informação. No entanto, apesar do YQL! disponibilizar essas tabelas para que possamos consultar informações, nem sempre existirá uma tabela para o que desejamos buscar. O que fazemos nesse caso?

Consultando informações de forma genérica

Para permitir que possamos consultar informações de variadas fontes, o próprio YQL! disponibiliza uma tabela chamada “html”. Essa tabela permite que seja feita requisições para qualquer URL procurando por algo dentro da resposta gerada. A pesquisa dentro do HTML é feita através de XPath, que é uma linguagem para fazer buscas dentro de documentos XML. (Caso você não conheça XPath, ou é como eu que vive esquecendo a sintaxe, uma boa referência é a seção no site da w3schools dedicada ao assunto.)

Para mostrar como fazer uma pesquisa genérica, vou utilizar como exemplo o calendário de cursos disponível na página inicial do site da Caelum. Para extrair as informações da tabela, o XPath adequado é o seguinte:

//div[@id='calendario']/table/tbody/tr

Traduzindo o comando: Em qualquer lugar do documento, busque uma div cujo id é calendario e dentro dessa div eu quero todos os tr que vão estar dentro de um tbody que vai estar dentro de um table.

Com isso, podemos montar nossa query da seguinte forma no YQL!:

select * from html where xpath="//div[@id='calendario']/table/tbody/tr" and url="http://www.caelum.com.br"

Ao executar essa query no console do YQL! o resultado retornado será todas as Tags <tr> da listagem dos cursos.

Criando sua própria tabela da forma simples

Agora que conseguimos realizar nossa consulta e buscamos as informações desejadas, podemos começar a melhorar os nossos resultados. O primeiro ponto é que deixar esse XPath explícito na query pode não ser algo tão agradável dependendo da utilização e situação. Nesse caso, queremos que a nossa consulta seja executada com um simples:

select * from caelum.proximoscursos

e ainda assim a query original deve ser executada. Muito mais agradável, não? Para isso, precisamos criar a nossa própria tabela.

O processo de criação de uma tabela do YQL! não é complicado, apesar que precisamos lidar com alguns XMLs a princípio. Primeiramente, precisamos criar um arquivo .xml com o nome de nossa tabela, nesse caso caelum.proximoscursos.xml. E definir alguns meta-dados, como autor e descrição da tabela. Além disso, no mesmo XML, dizemos qual é a query que deverá ser executada. Isso é feito através de um simples código Javascript, que é executado quando a query for disparada.

Esse Javascript fica dentro das Tags <bindings><select><execute> dentro do XML e é executado quando invocamos a tabela. Para executarmos a consulta, basta nesse Javascript adicionarmos o seguinte código:

var url = 'http://www.caelum.com.br';
var xpath = "//div[@id='calendario']/table/tbody/tr";
response.object = y.query('select * from html where url="' + url + '" and xpath="' + xpath + '"').results;

O objetivo desse código é fazer uma chamada ao serviço de queries do Yahoo! através da função query() passando a consulta que desejamos realizar e mandamos recuperar seu resultado. Nada mais que isso.

O resultado final desse XML pode ser visto em: http://ahalmeida.me/tabelas_yql/caelum.proximoscursos_html.xml

E para executá-lo no console do YQL!, basta importá-lo adicionando antes da query o comando “use” e executar a consulta:

use 'http://ahalmeida.me/tabelas_yql/caelum.proximoscursos_html.xml';
select * from caelum.proximoscursos_html;

Pronto! Tabela criada e pronta para o uso.

Complicando mais a tabela para melhorar os resultados

A tabela criada anteriormente possui um grande problema. Os dados retornados por ela ainda estão no meio de um HTML, cheio de formatação e sem nenhuma semântica com relação ao domínio da informação que desejamos buscar. Para melhorar isso, é preciso usar um pouquinho de Javascript para formatar o resultado que a query devolverá.

A ideia é que seja feito um parse do HTML retornado, para que seja devolvido um XML ou um JSON para que fique mais fácil trabalhar com as informações retornadas.

Para isso, é preciso escrever um pouco mais de Javascript na Tag <execute>. Diferentemente da tabela que retorna o proprio HTML, agora é precisar tomar algumas decisões sobre esse HTML e gerar um novo XML. Para parsear e criar um novo XML, uma forma possível de fazer isso no Javascript é através do E4X (ECMAScript for XML), para conhecer mais e aprender como usar, vale uma lida aqui.

Com o E4X é possível navegar no XML e realizar verificações e pegar valores. Com isso, pode-se a partir do resultado da query pegar as tags <tr> do mesmo da seguinte forma:

trs = query.results.tr;

E em seguida é possível iterar sobre todos os <tr> através do for each:

for each(var tr in trs) { ... }

Devido à estrutura do HTML retornado pela pesquisa, é retornado também um <th> com o nome do agrupamento por mês dos cursos, que não é necessário no retorno da pesquisa, por isso, podemos verificar se existe um elemento desse tipo dentro do <tr> e caso exista, ignoramos essa linha. Isso é possível, entre outras formas, através da seguinte verificação:

if(tr.elements('th').length() == 0) { /* entao não é a coluna do agrupamento do mês e podemos pegar os resultados */ }

Com isso agora é possível iterar sobre as células (<td>) da coluna e recuperar seus valores. Dessa forma haverá um outro for each para iterar nas células, e dentro de cada célula haverá uma verificação para saber em qual célula o for está posicionado no momento e com isso retirar a informação do HTML de forma adequada (dentro de um link, de uma tag <p> ou do atributo “title” do <td>).

O código completo dessa tabela pode ser encontrada no meu repositório no github (em breve vou mandar o pull request pro repositório oficial, quero fazer umas melhorias antes, como uns filtros por unidade :) ).

E para vê-la em produção, você pode executar o seguinte comando:

use 'http://ahalmeida.me/tabelas_yql/caelum.proximoscursos.xml'; select * from caelum.proximoscursos;

Conclusão

Criar tabelas no YQL! não é uma tarefa difícil, no entanto, as vezes pode ser uma tarefa um pouco maçante, por conta de todo o parsing do resultado da query. De qualquer maneira, é um código que será escrito uma vez e que raramente irá se alterar. Para saber TODOS os detalhes possíveis sobre a criação e utilização das tabelas, recomendo uma lida com calma na documentação do YQL!. No próximo post vou falar sobre como utilizar essa tabela criada em uma aplicação web.

Etiquetado ,

YQL! Parte 1: O básico sobre busca de dados públicos

O problema de buscar dados públicos

Muitas vezes precisamos que nossa aplicação disponibilize dados os quais não temos em nosso banco de dados. Isso é muito comum atualmente com aplicações que precisam exibir as mensagens mais recentes de uma pessoa no twitter, a lista de amigos de alguém no facebook ou até mesmo as informações sobre os hospitais disponíveis em uma dada região.

Em todos esses casos, as informações existem, mas não a temos em nossa aplicação. Justamente para isso, muitos serviços atualmente fornecem uma API para que seja possível recuperar e manipular esses dados. No entanto, o mundo não é perfeito e a grande maioria dos dados que precisamos não estão disponíveis em uma API que seja fácil de acessar. Consequência? Temos que usar os famigerados “crawlers”, que são scripts que acessam uma ou mais páginas em busca de informações que nos sejam úteis, mas nem sempre escrever um crawler é uma tarefa simples.

YQL! – Yahoo Query Language

Justamente para facilitar a consulta de dados públicos na internet, o Yahoo! criou uma ferramenta chamada YQL! (Yahoo! Query Language). O objetivo é que seja disponibilizada uma linguagem semelhante ao SQL, porém com o objetivo de realizar consultas em sites na web. Para utilizarmos, não precisamos de muito, basta acessar o console disponível em http://developer.yahoo.com/yql/console/ e brincar com as queries, recuperando um XML ou um JSON como resposta.

Primeira consulta: buscando algo no Yahoo! Answers

O YQL! já possui diversas tabelas disponíveis para consultarmos que nos abstraem toda a complexidade de pesquisar no site de determinado serviço. Por exemplo, podemos consultar sobre como dormir bem no Yahoo! Answers, para isso, basta executarmos uma query que busque na tabela answers.search por “how to sleep well”, mas que parâmetros temos de colocar em nossa query para isso? Podemos descobrir essas informações executando o seguinte comando:

desc answers.search

Grande parte das tabelas existentes no YQL! provêem uma URL de documentação (visível dentro da Tag documentationURL), de qualquer forma, caso a documentação não exista para alguma tabela, é possível também através do desc ver a lista de parâmetros que a query recebe e a partir daí inferir o uso.

Olhando a documentação da tabela vemos que o parâmetro “query” indica pelo o quê procuramos e teremos a seguinte consulta:

select * from answers.search where query=”how to sleep well”

Integrando com uma aplicação (qualquer linguagem)

Mas como faço para usar esses resultados na minha aplicação? Simples, o YQL! fornece uma API Rest a qual podemos invocar passando como parâmetro a query que desejamos realizar. Basta invocar http://query.yahooapis.com/v1/public/yql?q=SUA_QUERY_VEM_AQUI que o resultado é retornado. No próprio console, no painel inferior existe um campo com a URL já pronta para ser copiada e utilizada na sua aplicação.

Por ser uma URL simples, é possível invocá-la de qualquer aplicação cuja linguagem suporte requisições HTTPs. Dependendo da linguagem utilizada, é possível utilizar uma ferramenta que faça a requisição e auxilie no parsing do XML/JSON da resposta, como o Restfulie (que existe para várias plataformas) e o HTTParty no Ruby.

Tabelas públicas

No YQL! também é possível criar tabelas novas e disponibilizar essas tabelas para que outras pessoas possam utilizá-las, essas tabelas são conhecidas como “Community Tables” e pode ser criada por qualquer pessoa (a parte 2 cobrirá a criação de tabelas). Nessas tabelas disponíveis, é possível por exemplo, consultar informações no IMDB, buscar o status de uma encomenda no através do site dos correios (tabela feita pelo Guilherme Chapiewski), buscar dados de músicas e bandas no Last.fm assim por diante.

O uso dessas tabelas se dá da mesma maneira que o uso das tabelas já providas pelo Yahoo!, ou seja, vá até o console, teste a sua query até ela recuperar as informações da forma que você precisa e utilize a URL em sua aplicação (nas próximas partes desse post colocarei um exemplo de uso em uma aplicação Ruby, mas que pode ser aplicado facilmente em outras linguagens).

Conclusão

Essa primeira parte é só uma introdução sobre o YQL!. Algumas buscas vão requerer tarefas mais avançadas, como criar tabelas, fazer joins nas tabelas e assim por diante, que serão vistos nos próximos posts.

Etiquetado ,

Cross-domain AJAX requests with JSONP

AJAX requests are very common nowadays, because it can improve user experience on your application, and also boost it’s usability. Asynchronous requests can be used for instance, to invoke an URI in order to process some logic without committing the browser on waiting until the end of the request. So, the user can still use the page, even if the logic hasn’t finished yet.

Cross-domain AJAX call, what is the matter?

However, there is a scenario where an application A, at http://www.applicationA.com needs to do an AJAX request to an URI at application B, let’s say http://www.applicationB.com/aGivenURI.

When this request is done, you’ll be faced with the nice and meaningful message “Access to restricted URI denied.“, or some variation on this message. But, what the heck is happening here? Why I can’t do a request to this other site?

The problem is…. the application B is at other domain, and browsers, for security reasons, don’t allow one to make request for a domain which isn’t your own domain (or a sub-domain of your domain).

And now, what do I do, if I can’t do an AJAX request to MY application whose domain isn’t the same as the application B? You could possibly do a server side request to that URI, and it would work, however, this is not AJAX.

JSONP to the rescue

If we pay carefully attention, we CAN do cross-domain request on our HTML sources. If you add the following snippet to your code, at the application A:

<script src="http://www.applicationB.com/aGivenURI" type="text/javascript"></script>

This code DOES a call to the application B, so, now we are doing a cross-domain request. So, if we can make a cross domain request this way, what if we instead of doing and XMLHttpRequest for doing AJAX request, we just created these <script> blocks on the fly, dynamically, thus, having “almost” the same behavior from the AJAX request.

Why almost? What will the given URI give to us? Ok, it’ll give us back the JSON we needed, probably, simple as the following:

{message: 'New car added successfully', model: 'Ferrari'}

But, if it’s being added at our code, there’s just no way to retrieve this JSON. Because, it’s a javascript file that’s being imported to my page, dynamically. But this is easy, what if we just wrap this JSON under a function and just make the function return this JSON, that way, we could make a call to that function, and it’ll return the JSON we need. So, now, the javascript code retrieved from the application B will be:

saveInformations({message: 'New car added successfully', model: 'Ferrari'});

And now, all we need to do to retrieve this JSON is a call to the saveInformations function. It works as a callback function.

Generally, these javascripts are generated dynamically, and so, you would also might be able to choose the name of you callback function, most of the times, passing a parameter to the requested URI.

This technique that just consists on exploring the use of the <script> tag, and adding it dynamically to your page, making it possible to do cross-domain requests, and retrieve the value by defining callback functions, is called JSONP (JSON Padding).

Simplifying it with JQuery

JQuery makes it very transparent to use JSONP, it does all the boilerplate code to create the script tag dynamically and invoke the callback function. All you have to do is to define the parameter callback=?, and if the parameter is present, JQuery will do all the needed to do JSONP, otherwise, it’ll do a normal AJAX request.

$.getJSON("www.applicationB.com/aGivenURI?callback=?", function(data) {
    alert(data.model + " - - " + data.message);
});

Pretty simple.

Etiquetado , ,
Seguir

Obtenha todo post novo entregue na sua caixa de entrada.