viernes, 22 de febrero de 2013

Devolver xml, json o html con RESTEasy

RESTEasy
En esta serie de artículos sobre los servicios web REST hemos visto hasta el momento como hacer un programa sencillo Hola Mundo con RESTEasy y como crear un cliente Java y Javascript de ese servicio web para consumirlo desde javascript en una aplicación web y desde un programa java usando la librería RESTEasy. En un servicio web REST podemos devolver datos en varios formatos, ya sea texto plano, html, json o xml, en esta entrada veremos como devolver datos en los dos últimos y que anotaciones usar para que las cabeceras devueltas en la petición sean las correctas, que ventajas nos puede aporta y que problemas nos puede resolver.

Antes unos pequeños apuntes de porque nos puede interesar devolver json o xml. Unos de los motivos es que a medida que las aplicaciones web están ganando en complejidad estas están tendiendo a delegar en el cliente la parte de visualización en vez de ser el servidor el que devuelva html formateado directamente. Además de evitar cierta carga de proceso en el servidor y delegarla en los clientes ofreciendo una interfaz REST de la apliccación permitimos que terceros desarrollen sus propias aplicaciones y se integren consumiendo los servicios que ofrecemos.

Una vez explicadas algunas ventajas, veamos el ejemplo de como devolver json o xml en el servicio REST, en el siguiente código el servicio HelloWorldResource devolverá los datos de un objeto a través de los métodos getMensajeJSON y getMensajeXML. Los métodos del servicio puede anotarse con @Produces indicando el formato de los datos que se devuelve, en la clase MediaType hay constantes para muchos formatos. Si el formato en el que devolvemos los datos no está definido en la clase MediaType podemos definir uno específico con @Produces("text/html"):

La anotación @Produces es muy importante en el servicio REST ya que los métodos getMensajeJSON y getMensajeXML tienen especificada la misma ruta de petición en la etiqueta @Path, ¿como sabe entonces el servicio REST en que formato se han devolver los datos si la URL solicitada es la misma para ambos casos? La respuesta es empleando la información enviada en las cabeceras del protocolo http, más concretamente empleando la cabecera Accept que en este protocolo indica en que formato quiere el cliente los datos. En muchas aplicaciones es habitual encontrarse en que se realizan peticiones al servidor especificando como Accept text/html y resulta que el servidor devuelve los datos en formato json, xml u otro, la aplicación funcionará bien pero lo hace empleando el protocolo http de forma incorrecta, esto no ocurre con los servicios REST que en función de lo que se solicita en la petición así es el formato de los datos devueltos. En la siguiente imagen pude verse la cabecera Accept de la petición enviada por el cliente javascript.


En el ejemplo se devuelve una clase POJO con varios atributos que usa las anotaciones @XmlRootElement, @XmlElement, @XmlAttribute para indicar los datos y la forma de los datos a generar como resultado:

Para el cliente java desde el punto de vista del que lo usa la comunicación con el servidor y el formato en el que se transmiten los mensajes es transparente.


En el cliente javascript si usamos el formato json nos será más cómodo tratarlo en el navegador: En las siguientes imágenes las peticiones que se realizan desde el navegador con el cliente javascript, en la columna type se puede ver el tipo de datos devuelto en las peticiones:


Para que el ejemplo funcione deberemos incluir las dependencias org.jboss.resteasy:resteasy-jaxb-provider:2.3.5.Final y org.jboss.resteasy:resteasy-jettison-provider:2.3.5.Final.

Para finalizar, comentar que la combinación de ofrecer en la aplicación una API REST junto con librerías como Backbone.js que proporcionan un Modelo-Vista-Controlador (MVC) en el navegador accediendo al servidor para consumir el servicio puede dar lugar a aplicaciones más flexibles y fáciles de desarrollar entre otras cosas. Y esa es la tendencia hacia la que están evolucionado las aplicaciones web a medida que el propio lenguaje javascript y los navegadores aumentan sus capacidades.

En el siguiente enlace puedes encontrar el código fuente completo de este ejemplo y probarlo tu mismo en un servidor de aplicaciones como Tomcat. La siguiente entrada será como integrar RESTEasy con un framework de desarrollo web como Apache Tapestry.

Referencia:
http://www.jboss.org/resteasy
http://backbonejs.org
Código fuente completo del ejemplo Hola Mundo con RESTEasy

sábado, 16 de febrero de 2013

Cliente javascript y java de servicio web REST con RESTEasy

RESTEasy
Una vez que hemos desarrollado un servicio web REST tendremos que obtener un cliente para consumirlo ya sea con javascript, Java u otro lenguaje. En cualquier caso los clientes son mucho más sencillos de obtener en RESTeasy que en los servicios web basados en mensajes SOAP y XML haciendo uso de otras librerías a partir de la definición contenida en el WSDL como vamos a ver. Además, de poder ser consumidos desde un navegador a través de javascript.

Para el cliente Java deberemos tener la interfaz de ese web service con los métodos ofrecidos en el servicio, con las anotaciones adecuadas y que deberemos implementar en una clase. La interfaz del ejemplo Ejemplo sencillo de web service con RESTEasy sería:

Y la implementación:

Una vez tengamos la interfaz del web service REST y su implementación podemos hacer un programa java que lo use como cliente:

Apartir de esa interfaz podemos obtener el cliente y un programa que lo invoca con el siguiente código. La parte importante está en el uso de las clases RegisterBuiltin y ProxyFactory:

Y eso es lo mínimo necesario para consumir los web services desde java ¿te pareció sencillo?, pues para consumirlos desde un navegador con javascript es aún más sencillo, veamos como. RESTEasy proporciona un servlet que genera un archivo js con los clientes javascript de nuestros servicios web REST, lo único que deberemos hacer es incluir ese servlet en el web.xml de nuestra aplicación web y usarlo en la página html en la que queramos hacer uso de él.

El servlet que generará el javscript, resteasy-jsapi, debe ser cargado después del servlet de RESTeasy por eso los valores de los load-on-startup en las etiquetas servlet, si no lo hiciéramos así obtendríamos la siguiente excepción de error:

En el archivo helloworld-resteasy.jsp está como es la llamada al web service desde el navegador, básicamente consiste en generar un html que incluya la etiqueta script haciendo referencia al javascript a obtener en el navegador, contendrá los clientes javascript de todos nuestros web services REST. Aunque en el uso de los clientes las peticiones que se producen a través de la red estas operaciones son totalmente transparentes para nosotros, en cada correspondiente cliente javascript tendremos disponibles unos métodos que se encargarán de realizar y de la forma adecuada las peticiones teniendo entre otras cosas en cuenta como enviar los parámetros de los métodos. Una cosa a tener en cuenta es que en la interfaz del web service REST no debemos usar sobrecarga, mismo nombre de método con diferentes parámetros, ya que de otra manera el cliente javascript no sabe distinguir a que método del Servicio web llamar.


Recursos que pide el cliente Javascript
El último paso que tendremos que aprender es como devolver otros tipos de datos más complejos como json, xml, html u otros.

Referencia:
REST
Ejemplo sencillo de servicio web con RESTEasy
Código fuente completo del ejemplo Hola Mundo con RESTEasy

sábado, 9 de febrero de 2013

Ejemplo sencillo de servicio web con RESTEasy

RESTEasy
Las arquitecturas orientadas a servicios (SOA) no son nuevas y existen desde hace ya bastante tiempo. Surgen por la necesidad de las aplicaciones de comunicarse entre ellas para intercambiar información y colaborar. Dada la heterogeneidad de las mismas aplicaciones en el lenguaje de programación o de representación de datos requieren un lenguaje común con el que intercambiar información, para ello se puede emplear un lenguaje de marcas como XML y para el intercambio de mensajes SOAP (Simple Object Access Protocol) sobre el protocolo HTTP. Otras opciones como CORBA los mensajes se transmitían de forma binaria. Pero los servicios web basados en XML y SOAP no están exentos de problemas, los mensajes SOAP son bastante complejos y para algunas necesidades no son fáciles de construir o cómodas de usar, por ejemplo desde un navegador o un dispositivo móvil empleando javascript.

Dado el auge u omnipresencia que están tomando los servicios basados en internet, la web, los navegadores y javasctipt muchos de los sitios más importantes están evolucionando hacia servicios REST por su simplicidad de ser consumidos y fácil acceso, muchos sitios ofrecen una API basada en REST para que terceros puedan integrase con ellos, este es el principio para poder construir mashups. Algunas de sus características son que emplean el protocolo HTTP y sus diferentes métodos (GET, POST, DELETE y PUT, etc.) asignando a cada uno de ellos una operación de las denominadas CRUD (create -> PUT/POST, retrieve -> GET, update -> PUT/POST, delete -> DELETE). Pueden devolver datos en cualquier formato pero normalmente se emplea JSON o XML. En el siguiente enlace, muy recomendable, sobre algunos conceptos sobre las APIs REST está muy bien explicado las ideas sobre las que se basan estos servicios.

Para hacer sevicios web basados en REST con Java disponemos de varios frameworks entre ellos Restlet o Jersey, sin embargo, me ha convencido el ofrecido por la comunidad de JBoss, RESTEasy, tiene una muy buena documentación que está bien explicada y con la que es muy fácil iniciarse. Por lo tanto a continuación voy a poner lo necesario para implementar el ejemplo Hola Mundo con RESTEasy en una aplicación web java que puede ser hospedada en cualquier servidor de aplicaciones como Tomcat o JBoss.

Con RESTEasy los servicios web son POJO (Plain Old Java Object) a los que se les añade la fucionalidad mendiante anotaciones. Veamos como de simple podría ser el típico ejemplo sencillo de web service Hola mundo como demostración.

Aquí vemos varias anotaciones @Path, @GET y @PathParam. Con la primera estamos indicando parte de la URL en la que el web service responderá, con la segunda indicamos que el método HTTP que llame a esa URL deberá ser get y con la tercera recogemos un parámetro indicado en la URL. La implementación sería:

Una vez que disponemos del web service deberemos añadir al archivo web.xml las cosas necesarias para que RESTEasy recoja las llamadas a las URLs de los servicios web y los invoque, entre ellas el servlet de nombre resteasy de la clase HttpServletDispatcher. El web.xml sería el siguiente:

Lo básico a añadir es el servlet de RESTEasy y el correspondiente servlet-mapping, también deberemos indicar el parámetro de contexto «resteasy.servlet.mapping.prefix» con el prefijo de la ruta del servlet-mapping del servlet de RESTEasy. Con esta configuración todas las URLs que lleguen a la aplicación web y con la ruta «/rest/» corresponderán a un web service REST, una cosa a destacar es que los servicios web pueden convivir con con el resto de la aplicación independientemente del framework que uticemos para desarrollarla, lo único que deberemos hacer es indicar un prefijo para el servlet de RESTEasy tal y como hemos hecho en el ejemplo.

Pero... ¿Como sabe RESTEasy cuales son los servicios web de la aplicación? La forma de indicarle a RESTEasy los servicios web es mediante una clase que extiende de javax.ws.rs.core.Application y utilizando el parámetro de inicialización javax.ws.rs.Application para el servlet de RESTEasy que se puede ver en el web.xml. La implementación no tiene más que un Set con las implementaciones de los servicios web, en el caso del ejemplo:

Para finalizar, comentar que RESTEasy se puede configurar también como un filtro, lo que tiene algunas ventajas como descubrir de forma dinámica los servicios web sin necesidad de la clase Application. El resultado del servicio web invocado desde un navegador web es:


Este es el primer artículo de unos que escribiré sobre RESTEasy, en el siguiente explicaré como crear un cliente javascript o java para consumir este servicio web y en el último hablaré de como devolver datos en formato JSON o XML desde el web service.

Referencia:
Código fuente Hola Mundo con RESTEasy
Conceptos sobre APIs REST
http://www.jboss.org/resteasy
http://stackoverflow.com/questions/4131968/resteasy-path-requiring-a-full-path

viernes, 1 de febrero de 2013

Reproductor de radios Jamendo con Python

Jamendo

Python
Si sigues este blog desde hace un tiempo sabrás que de vez en cuando comento alguna cosa relacionada aunque sea de forma indirecta con la Raspberry Pi ya que es el computador que uso para realizar las descargas via torrent y para reproducir música principalmente con cmus. Dado que la uso sin ningún entorno de interfaz gráfica sino simplemente conectándome via SSH desde mi portátil y trabajando a través de comandos desde la terminal casi todo lo que quiera hacer con ella lo tengo que hacer a través de la terminal.

Para escuchar música suelo hacerlo de varias maneras: escuchar mi propia música en mp3 con cmus, escuchar radios que emitan por internet vía streaming o también las radios de Jamendo a través del reproductor de su página web. Jamendo ofrece una API a través de la cual se pueden escuchar las radios. Esto es lo necesario para poder escuchar las radios de Jamendo desde la RPi utilizando la terminal. Como quería aprender algo de Pyhton y es uno de los objetivos RPi me puse manos a la obra a hacer un pequeño programa, aún no sabiendo nada de este lenguaje de programación, que me permitiese escuhar cualquiera de las radios de Jamendo via streaming.

El resultado lo podéis encontrar en mi repositorio de GitHub en un archivo que no llega a las 100 líneas de código Python. Básicamente utiliza la API Rest que ofrece Jamendo para los desarrolladores que devuelve la información en formato JSON. Permite listar las radios disponibles en Jamendo según el estilo de música y los identificativos que utilizaremos luego para indicar al programa la radio que queremos escuchar.

Para usar el programa necesitaremos tener Python instalado y dado el que reproduce la música realmente es el programa mpg123 necesitaremos instalar también su paquete.

Después de habernos descargado el programa y habiéndole dado permisos de ejecución con:


Podemos obtener un listado de las radios con su nombre e identificativo usando:


Una vez que sepamos la radio que queremos escuhar lo haríamos con, en caso de que fuese la radio Classical:


Este programa se puede usar en cualquier sitio que tenga esas dependencias aunque en un ordenador de escritorio o portátil no nos sea imprescindible como en el caso de la Raspberry Pi ya que en los primeros podremos usar el reproductor web de Jamendo. Aún así aquí está para quien le pueda resultar útil como a mi. El programa no capturará todas las condiciones de error que se puedan producir, tener en cuenta que está realizado por alguien que sabe programar, conoce el lenguaje y API de Java pero no de Python. En cualquier caso si alguien cree que puede ser mejorado solo tiene que comentarmelo, enviarme un parche, ... ;)

Referencia:
Guías de instalación Raspberry Pi y desempaquetado
4 formas de escuchar música a través de internet