Javafree

Um simples cliente da API do LastFM com RESTEasy

Publicado por jesuino em 17/03/2014 - 6.661 visualizações

Olá pessoal.

Nesse artigo vamos criar um simples cliente de API usando a biblioteca RESTEasy. Iremos usar a versão 1.2 da biblioteca da JBoss. Como "cobaia", vamos usar a API de busca de artista do Last.FM, pela simplicidade. O ambiente de desenvolvimento é o Eclipse.

A API de busca do Last.FM


A API do Last.FM é muito poderosa. A parte de busca do artista é um pequeno pedaço de tudo que a API oferece. Como desvantagem dessa API podemos citar o uso de API Key mesmo para uma simples busca(aproveite e já se inscreva para ter a sua chave, você vai ter que ter uma para prosseguir nesse tutorial!).
Sobre a API especificamente, a URL base é:


http://ws.audioscrobbler.com/2.0/


Na busca de artista, temos que enviar como parâmetros obrigatórios o método da API(method=artist.search), o nome do artista(artist) que você está procurando e a sua chave (api_key). O exemplo de URL na página deles, você pode acessar no seu navegador para fazer um teste:


http://ws.audioscrobbler.com/2.0/?method=artist.search&artist=cher&api_key=b25b959554ed76058ac220b7b2e0a026


A resposta contém diversos campos interessantes. Abaixo uma amostra da resposta que eu tive quando tentei acessar a URL acima



Deixamos claro nesse ponto que a API do Last FM não segue as coisas bonitas do REST(ROA - Resource Oriented Architeture, olha que nome bonito), descritas no livro RESTful WEB Services! Está mais para uma API RPC(remote procedure call, tem uma discussão intensa sobre o que é REST e o que é RPC), assim como a API do Flickr. No entanto, é perfeitamente possível consumir ela usando o RESTEasy...
Outro ponto que podemos criticar na API também, que desrespeita os modelo arquitetural REST, é o pecado de não linkar recursos. Por exemplo, na busca de tracks:


http://ws.audioscrobbler.com/2.0/?method=track.search&track=i%20want%20break%20free&api_key=b25b959554ed76058ac220b7b2e0a026


temos a resposta um monte de tracks, e nos tracks o nome do artista, mas não a URL para o artista.

Mas por outro lado a API é bastante completa e também utiliza OpenSearch

Toda a simplicidade de RESTEasy



RESTEasy está na versão 2.2 e estamos usando a 1.2. O motivo é pela maturidade da versão 1.2. Claro que a 2.2 está recheada de coisas legais, mas a 1.2 serve perfeitamente para nosso objetivo.
Esse tal de REST que todo mundo fala é o estilo arquitetural proposto por Roy Fielding há uns anos atrás. HTTP, o protocolo da WEB, cabe muito bem nesse modelo, tem tudo que precisamos para cumprir o REST. Bem, temos muito para falar sobre o REST, cada semana mais coisas são ditas, sem falar da guerra SOAP X REST. Mas hoje nosso objetivo é falar do RESTEasy.
Vendo o crescimento do REST e a dominância dele em APIs pela WEB, criaram uma JSR para WEB Services feitos em REST, a JSR 311. RESTEasy implementa essa especificação. Mais do que isso, incluem diversas outras características que até possam servir de base para novas versões da especificação.
Mas o que estamos interessados hoje não é criar WEB Services, mas sim consumir. O RESTEasy vem com uma parte da API voltada para consumir WEB Services REST. É essa parte que vamos usar nesse artigo.
A API do RESTEasy cliente é interessante, pois permite que você realize o consumo de WEB Services REST através basicamente de duas formas, também garante certa flexibilidade ao permitir que você troque o cliente HTTP. A parte mais impressionante é a capacidade da API de deixar você utilizar POJOs para os recursos e uma interface em comum com o servidor para os serviços em si (com alguma limitações). Realmente é algo inovador e útil.

Senta que lá vem código (ou senta e comece a escrever código)


Vamos lá! Baixe o RESTEasy 1.2.1. Crie um projeto Java no eclipse e adicione os jars do RESTEasy no build path do seu projeto(eles estão em /lib). Adicione todos, mas é importante deixar claro que em uma aplicação cliente nem todos são usados, isso pode ser selecionado usando Maven.
Crie um pacote chamado "principal" no seu projeto e dentro dele uma classe chamada "Principal", aproveite para o criar o método main, vamos fazer nosso primeiro acesso a API do Last.FM.
A parte cliente do RESTEasy basicamente divide-se no ClientRequest e no ClientProxy. Iremos usar o ClientRequest nesse exemplo.
Para criar objetos do ClientRequest usamos uma fábrica, não instanciamos ele diretamente. Esse fábrica nos dá o objeto e deles fazemos a requisição para o servidor. Abaixo já temos uma busca no Last.FM(lembre-se de substituir a {API_KEY} da url por sua api key), mas o corpo está em uma String plana, seja "printado" no seu console o JSON da busca:


Eita, três linhas de código(tirando as coisas do cotidiano)! Agora é só pegar essa String com o XML, fazer um tratamento com REGEX e então tirar o que queremos. Não. Longe disso. JDOM? Sax? Não, não e não :).
Usando JaxB é possível realizar o parse dessa String diretamente para objetos Java. Em outras palavras, temos que criar POJOs e adicionar anotações do JaxB, tais como @XmlRootElement, e vamos ter a resposta diretamente em objetos Java!

Criando classes de modelo


Vamos agora escolher alguns campos que nos interessam e criar classes simples Java que descrevem a resposta da API do Last.FM. Para isso, crie um pacote chamado "model".

Vamos começar modelando o Artista em sí. O que queremos saber de um artista? Iremos pegar os atributos nome, url e as imagens do artista. Já está bom, depois você pode estender a classe simplesmente adicionando atributos que lhe interessa. Na resposta da API, os campos que correspondem a esses atributos são: name, url e image (uma lista delas!). Abaixo temos então nossa classe Artista:



Repare as anotações do Jaxb, com elas fazemos o mapeamento da nossa classe para o XML que será recebido. Você pode encontrar bons tutoriais sobre Jaxb aqui e aqui.
Para criar seus POJOs e anotar corretamente os mesmo, você deve conhecer intimamente a resposta, o que será "parseado". Então, se tiver dúvidas no que foi feito, volte para o XML de resposta e verifique ao qual elemento corresponde cada atributo e vai entender por que as anotações foram feitas do jeito que estão.
Observe que vem de javax.xml.bind.annotation. Nesse pacote não temos nenhuma implementação, não faz nada. Quem implementa o Jaxb é um provedor. Com o RESTEasy em seu classpath, o provedor do RESTEasy é que vai fazer o parse.
O artista está terminado, mas temos mais informação dentro dessa resposta, como o elemento results e o elemento raiz lfm. Dentro do próprio artista temos a classe imagem. Vamos modelar esses elementos também para classes, pegando alguns atributos que achamos interessantes:
Classe Imagem
Simplemesmente modelamos a imagem. Lembre-se na resposta da API a imagem simplesmente tem um atributo(size) e o valor dela em si.

Classe ResultadoBusca
Nessa classe o mais interessante é o uso da anotação @XmlElementWrapper. Com ela podemos diretamente informar que a nossa List no código Java é uma lista de Artistas. O nome do elementWrapper é a tag que identifica o início da lista. Sem esse recurso teríamos que criar uma classe só para fazer o wrapping, ou seja, uma classe que teria uma lista de artistas. Outro ponto interessante é o uso do namespace do OpenSearch.

Classe LastFmResposta
Essa classe é meio chata, só tem de legal o atributo "status", que informa como foi o acesso a API. No entando, mais a frente vamos falar de uma vantagem interessante de termos classes assim, top level, separadonas.

Ufa, terminamos por enquanto \o/. Imagina quantos POJOs não teríamos se fossemos fazer um sistema de busca para toda a API?
Eu disse que teria uma vantagem do XML ser bem estruturado assim. A vantagem é que com Jaxb podemos reusar as classes que descrevem partes do XML(a classe imagem pode ser usada na classe Album, se fizessmos a busca de albuns também) e a melhor parte ainda é que podemos arquiteturar nossas classes para termos comportamento que varia dependendo da busca feita. Sim senhores, polimorfismo, ou melhor, a pura implementação do padrão estratégia! Um exemplo disse está na classe LastFmResposta. Colocamos o ResultadoBusca como uma classe concreta, mas poderíamos ter coloca como uma interface e trocar a implementação de acordo com a busca sendo feita. Exemplo:



Ou então poderíamos manter o ResultadoBusca como classe concreta, mas dentro dela fazer como interface o recurso(artista, album, track, etc...). Porém(sempre tem um porém), outra "falha"(entre aspas, pois é mais uma opinião pessoal) da API nos leva a um dilema. Essa falha é que a API muda a tag do resultado da busca dependendo do recurso. Para Artista temos "artistmathes", para tracks "tracksmatches". Mas, malandro que somos, podemos fazer essa lista sofrer um wrapping através de outra classe e nessa classe trocar o valor da tag que representaria a lista dos resultados. Sugiro ao leitor a se aventurar nessa missão e depois compartilhar os resultados :). Mais sobre interface e Jaxb você pode encontrar aqui.

Até agora modelamos as classes, mas nem testamos como ficou. Então chega de blá blá e "vamu bora".

Criando uma pequena aplicação


Agora vamos criar uma pequena aplicação que vai pegar a entrada do usuário, realizar a busca chamando a API do LastFM e retornar na linha de comando a resposta da API de uma forma amigável.
A primeira implementação abaixo é simples, só lista os artistas para um artista "hard coded" na URL, no caso Queen. Altere sua classe principal como abaixo e execute



Bem simples não? A resposta deve ser algo como abaixo:


ok
Sua busca por Queen trouxe 4167 resultados:
Queen
http://www.last.fm/music/Queen
Imagem small: http://userserve-ak.last.fm/serve/34/45625545.png
Imagem medium: http://userserve-ak.last.fm/serve/64/45625545.png
Imagem large: http://userserve-ak.last.fm/serve/126/45625545.png
Imagem extralarge: http://userserve-ak.last.fm/serve/252/45625545.png
Imagem mega: http://userserve-ak.last.fm/serve/500/45625545/Queen+PNG.png


--
The Good, the Bad & the Queen
http://www.last.fm/music/The%2BGood%252C%2Bthe%2BBad%2B%2526%2Bthe%2BQueen
Imagem small: http://userserve-ak.last.fm/serve/34/181190.jpg
Imagem medium: http://userserve-ak.last.fm/serve/64/181190.jpg
Imagem large: http://userserve-ak.last.fm/serve/126/181190.jpg
Imagem extralarge: http://userserve-ak.last.fm/serve/252/181190.jpg
Imagem mega: http://userserve-ak.last.fm/serve/500/181190/The+Good+the+Bad++the+Queen.jpg


--
Queen & David Bowie
http://www.last.fm/music/Queen%2B%2526%2BDavid%2BBowie
Imagem small: http://userserve-ak.last.fm/serve/34/265219.jpg
Imagem medium: http://userserve-ak.last.fm/serve/64/265219.jpg
Imagem large: http://userserve-ak.last.fm/serve/126/265219.jpg
Imagem extralarge: http://userserve-ak.last.fm/serve/252/265219.jpg
Imagem mega: http://userserve-ak.last.fm/serve/_/265219/Queen++David+Bowie.jpg


(...)


Se você trocar o valor do parâmetro q e executar novamente(lembrando que o parâmetro deve ser codificado para URL), deveremos ter outro resultado. Olhe a resposta para Bob Marley (Bob%20Marley):

ok
Sua busca por Bob Marley trouxe 0 resultados:
Bob Marley
http://www.last.fm/music/Bob+Marley
Imagem small: http://userserve-ak.last.fm/serve/34/77849.jpg
Imagem medium: http://userserve-ak.last.fm/serve/64/77849.jpg
Imagem large: http://userserve-ak.last.fm/serve/126/77849.jpg
Imagem extralarge: http://userserve-ak.last.fm/serve/252/77849.jpg
Imagem mega: http://userserve-ak.last.fm/serve/_/77849/Bob+Marley.jpg


--
Bob Marley & The Wailers
http://www.last.fm/music/Bob%2BMarley%2B%2526%2BThe%2BWailers
Imagem small: http://userserve-ak.last.fm/serve/34/18722345.jpg
Imagem medium: http://userserve-ak.last.fm/serve/64/18722345.jpg
Imagem large: http://userserve-ak.last.fm/serve/126/18722345.jpg
Imagem extralarge: http://userserve-ak.last.fm/serve/252/18722345.jpg
Imagem mega: http://userserve-ak.last.fm/serve/500/18722345/Bob+Marley++The+Wailers+A217641142465829.jpg


--
Bob Marley vs. Funkstar Deluxe
http://www.last.fm/music/Bob+Marley+vs.+Funkstar+Deluxe
Imagem small: http://userserve-ak.last.fm/serve/34/63201371.jpg
Imagem medium: http://userserve-ak.last.fm/serve/64/63201371.jpg
Imagem large: http://userserve-ak.last.fm/serve/126/63201371.jpg
Imagem extralarge: http://userserve-ak.last.fm/serve/252/63201371.jpg
Imagem mega: http://userserve-ak.last.fm/serve/500/63201371/Bob+Marley+vs+Funkstar+Deluxe+17384.jpg
(...)


Mas convenhamos que ficar mexendo em código, compilando não é algo que você gostaria de ficar fazendo quando precisasse fazer uma busca de artista, né? Então vamos alterar esse código para pedir para o usuário o nome do artista executar a busca, fazer o encoding e apresentar o resultado. Abaixo o código novo. Repare que temos alguns comentário numerados, vamos expĺicar cada um desses pontos do código novo.


Explicando o código

  1. Separamos a API para facilitar a troca se precisarmos. Poderíamos também ou pedir para o usuário passar uma API Key como parâmetro na execução do programa, ou colocar a API Key em um arquivo que seria lido pelo programa

  2. Iremos ficar pedindo a entrada do usuário eternamente até que ele entre aperte um enter sem entrar texto nenhum

  3. Nesse método estático usamos a classe scanner para pegar a entrada do usuário. Colocar isso em um método evitou que tivessemos que repetir o codigo que imprime a mensagem que pede a entrada do usuário

  4. Para fazer o encoding do texto que o usuário entrou, usamos esse método. Assim se o usuário entrar espaços ou outros caracteres que precisam ser codificados, esse método fará o trabalho para nós!

  5. Aqui uma simples verificação para imprimir somente imagens que existem. Dependendo do artistas, podem não existir imagens em alguns tamanhos.



Enfim, o seu código deverá exibir no console algo como o seguinte:


>>>> Busca de artistas usando a API do LastFM! <<<<


>> Entre o nome do artista a ser buscado (ou só pressione Enter para sair)

the thashmen

>>>>Realizando a busca... Aguarde um momento por favor

ok
Sua busca por the thashmen trouxe 1 resultados:


--
The Thashmen
http://www.last.fm/music/+noredirect/The+Thashmen

>> Entre o nome do artista a ser buscado (ou só pressione Enter para sair)


Até mais!


Outra forma do RESTEasy Cliente


Nesse artigo da DZone, são apontadas três formas de usar o RESTEasy client. Iremos mostrar agora como realizar o mesmo cliente usando interfaces de proxy.
Segundo a documentação do RESTEasy, essas interfaces servem para descrever os serviços que pretendemos acessar. A biblioteca vai pegar essa interface, as anotações e converter em requisições HTTP, mas tudo isso invisível para nós! Para usar essa maravilha, primeiramente devemos fazer uma interface que contém os métodos que queremos acessar com as respectivas anotações do Jaxrs(veja a especificação JSR 311 para mais detalhes!), então, crie um novo pacote na raiz do seu projeto, nomeie esse pacote como servicos e crie uma interface nele. Eu chamei a interface de ArtistaServico, nome super tosco pra variar... Olhe como ficou a interface:



Agora com os mecanismos do RESTEasy, quando chamarmos esse método getArtistas, usando uma implementação da interface que o RESTEasy cria pra nós, teremos nossa resposta.

Perceba que por causa da API ser RPC, separamos o parâmetro method da URL para como sendo um parâmetro do nosso método. Pode parecer ruim no nosso contexto, mas, mais uma vez, se fossemos realizar um projeto mais bem arquituralmente desenhado, poderíamos ter um grande reuso, principalmente esse método, que poderia ser um get genérico e tudo mudar de acordo com o método. Mantivemos a forma que está no projeto atual para ser mais simples, senão perderíamos o foco de simplemente aprensentar um cliente com RESTEasy.
Pode parecer ser melhor usar ClientRequest agora, mas em projetos grandes/médios essas organização por interfaces facilita muito a manutenção, ainda mais com o mapeamento de path, podemos mexer nas anotações da interface sem nem mesmo mexer no nosso código que realmente consome o serviço e o projeto funcionará sem problemas.
Vamos agora usar essa interface. Copie e cole a classe Principal e nomeie a cópia como PrincipalComProxy. Olha como fica a nossa implementação agora:




Vejam como ficou mais limpa a chamada do serviço. Eu particularmente gostei muito dessa forma de criar clientes, principalmente por que podemos criar uma interface compartilhada com o servidor e o cliente.
É, fomos surpreendidos novamente. Há essa possibilidade de compartilharmos a interface que descreve os serviços no cliente e no servidor. A documentação descreve falhas de se fazer isso. A principal falha é que teremos que retornar um objeto POJO e não o objeto Response, ocultando detalhes de como andou a requisição, no entanto, a mesma documentação sugere formas de arrumar isso!
Sendo mais prático, imagine que o Twitter tenha usado RESTEasy no cliente. Então, invés de você ter que escrever todo o mecanismo de acesso a API deles, eles simplesmente poderiam oferecer essa interface e você poderia usar em seus projetos como mostrado no exemplo acima!


Tudo fica mais legal com interface gráfica!


Está tão legal ficar acessando nosso artistas pela linha de comando, mas hoje pode ficar melhor ainda! Para fechar com chave de ouro nosso projetinho, vamos montar uma pequena Tela usando java swing e exibindo o resultado da busca. Abaixo o cliente que montamos aqui, funcionou legal é já uma aplicação interessante. É claro que para você conseguir uma popularidade precisará muito mais do que uma simples busca de artista. Talvez um cliente completo para a API do LastFM e você pode conseguir alguns usuários para seu sistema :).

Chega de papo e vamos lá, crie um pacote chamado view e dentro dele uma classe BuscaArtistaView que estende de JFrame.
Nosso foco hoje não é Java Swing, então criamos uma classe simples com código do tipo "salsiçhão", sem se preocupar muito com a beleza do código, senão perderíamos muito tempo falando de Swing.
Nossa tela vai ser super simples: um campo de texto, uma busca, uma lista mostrando os resultados e um label que tenta mostrar o status da busca. Clicou na linha da lista, mostra a foto do artista correspondente e a URL para a página dele... Também vamos colocar menu para permitir que você configure a chave da API e saia do sistema. A aplicação é daquelas chatas, que ficam mostrando diálogos o tempo todo. Tudo para mantermos a simplicidade!
Abaixo está nosso código com alguns comentários relevantes.


Aqui uma imagem mostrando a cara da aplicação.
Nosso simples cliente em Java Swing

Você pode conferir o projeto anexo, só tome cuidade com os problemas de classpath, pois eu uso uma variável para indicar as bibliotecas do RESTEasy.

Conclusão


Mostramos um simple cliente de API usando o RESTEasy, consequentemente exploramos a API client do RESTEasy. Ainda há muito a ser dito e melhorado no que foi exposto, mas acredito ser um bom começo para quem quer conhecer esse lado da API. Se tiver dúvidas ou necessitar de ajuda no projeto, use o fórum, por favor.

E agora?


Fica o desafio da montagem de um cliente de toda a API do LastFM. Como puderam ver, a api é simples de ser usada e também divertida. Outro ponto é melhorar o código da GUI em JavaSwing.


Download:  LastFM.png
Size:  342 KB

Download:  RESTEasySimpleClient.tar.gz
Size:  14 KB

comentários: 6

Tópicos Relacionados