Desarrollo de aplicaciones en HTML5 para AppUp℠
Parte 5: Una aplicación cliente
de Twitter
Introducción
La presente entrega de nuestra serie sobre desarrollo de aplicaciones en HTML5 se enfoca en autenticarse con un servicio remoto y mostrar la información obtenida de ese servicio. Cubre el uso de xmlhttp para la comunicación con en el servicio remoto, OAuth para autenticarse con él, llamadas para manejar los comandos http completados y el uso de local storage de HTML5 para salvar la información entre las ejecuciones de la aplicación.
Para este ejemplo usaremos Twitter como nuestro servicio remoto. Una vez autenticados, el cliente de Twitter mostrará nuestros feeds y permitirá filtrar los tweets que hayan sido retweeteados por nosotros o por alguien a quien estemos siguiendo en Tweeter.
Todos los archivos mencionados en este artículo pueden ser descargados aquí.
Twitter en dos palabras
Twitter es un servicio de microblogging que te permite recibir posts breves de las personas que sigues en tu cuenta. Cuando alguien postea una actualización ésta es distribuida automáticamente a todos sus seguidores. Esta actualización es conocida como un Tweet. Si un seguidor repite o replica esta actualización para que la lean sus propios followers estamos en presencia de un "retweet" (RT).Descripción del cliente de Twitter
Este sencillo cliente conecta con Twitter usando tu propia cuenta y muestra los últimos Tweets de las personas a quien sigues. La primera vez que te conectes deberás proveer tu nombre de usuario y contraseña de Twitter para establecer la conexión. En ese momento los últimos feeds son recuperados y mostrados en la ventana principal. En la parte superior de la pantalla hay botones que te permitirán filtrar los tweets mostrados: Retweeteados por mí, Retweeteados a mí, Retweets míos y Todos los mensajes. La última opción desconecta y cierra la aplicación.
Imagen 1: Pantalla principal del cliente de Twitter
Hablando con Twitter
Twitter soporta tres APIs para comunicar con sus servicios; nuestro cliente de Twitter usa la API REST (REpresentational State Transfer). La API de Twitter es enteramente basada en HTTP, lo que significa que mucho del código se encarga de generar y recibir tráfico HTTP. Todo lo que puedes desear saber acerca de comunicación con la plataforma de Twitter puedes hallarlo en el sitio de Desarrolladores de Twitter.
Antes de que el cliente pueda mostrar el tráfico del usuario éste debe autenticarse para actuar "en nombre" de dicho usuario. Twitter utiliza el standard abierto de autenticación OAuth para ello. OAuth permite al cliente obtener una señal de acceso que es utilizada para firmar cada pedido hecho a la API, la que identifica el tráfico como autorizado para conectar con la cuenta de Twitter del usuario. El proceso se describe detalladamente en esta página. En particular, si sigues el enlace querrás revisar el diagrama y los ejemplos de código que se muestran allí.
Los pasos básicos para el proceso de autorización:
- Solicitar señal de acceso a Twitter
- Twitter devuelve señal de acceso desautorizada
- El cliente redirecciona a la página de autorización de Twitter.
- El usuario da el OK para que el cliente acceda a su cuenta
- La página de autorización de Twitter solicita un PIN
- El usuario introduce el PIN en el cliente
- El cliente usa el PIN para obtener señal de acceso autorizada
- El cliente utiliza esta señal para operar "en nombre" del usuario.
Una vez autenticado, el cliente simplemente utiliza tráfico http GET y POST para recuperar y mostrar los feeds del usuario. Nuevamente, puedes referirte a la documentación de la API de Twitter.
Dentro de la aplicación
La funcionalidad principal del cliente está escrita en JavaScript (observa el archivo
index.js file dentro de la carpeta js). Cuando la aplicación carga la función
onLoad es llamada; esta función revisa si el cliente corrió anteriormente
alguna vez y si la señal de acceso autorizada fue recuperada y almacenada localmente. Si es así,
llama a authenticationComplete que utiliza esa señal para obtener los
tweets del usuario.
function onLoad() {
var body = document.getElemenById('bodyId')
if (typeof(localStorage) != 'undefined' ) {
var tmp_oauth_token = localStorage.getItem('user_oauth_token');
var tmp_oauth_token_secret = localStorage.getItem('user_oauth_token_secret');
if (tmp_oauth_token != null && tmp_oauth_token_secret != null
&& tmp_oauth_token != '' && tmp_oauth_token_secret != '') {
user_oauth_token = tmp_oauth_token
user_oauth_token_secret = tmp_oauth_token_secret
authenticationComplete()
return
}
}
body.innerHTML = '<div id="title">Twitter Client</div><div>Click on
the "Get PIN" button below. It will open a new window where you can pass the
authentication information and get a PIN code. Then enter the PIN code in the box below
and click on "Sign In."<br><a class="button small white" href="#"
onclick="getPin()">Get
PIN</a></div><br><br><div><input id="pinCode"
type="text"/><a class="button small white" href="#" onclick="signIn()">Sign
In</a></div><br><div id="errorStr"></div>'
}
Transcripción 1: Función onLoad del archivo index.js
Si el cliente no fue autenticado, onLoad presenta una pantalla sencilla
con un botón que conectará con la página de autenticación en Twitter; el botón hace
esto a través de las funciones getPin/twitterRequest. Nótese
que la tercera línea de twitterRequest registra
getTwitterRequestAnswer como una función de callback (devolución de
llamada); esta función es convocada cada vez que cambia el readyState. Se verá el
uso de callbacks similares a través del ejemplo.
Imagen 2: Pantalla principal del cliente cuando no hubo autenticación
Imagen 3: Pantalla de autenticación con Twitter
function twitterRequest() {
if (xmlhttp) {
xmlhttp.onreadystatechange = getTwitterRequestAnswer
var url = 'https://api.twitter.com/oauth/request_token'
initRequest('POST', url, [['oauth_callback','oob']])
xmlhttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
xmlhttp.setRequestHeader('Accept-Language', 'en')
xmlhttp.send()
}
}
La función getTwitterRequestAnswer corrobora que el pedido se haya realizado satisfactoriamente, analiza la respuesta y usa la información de la respuesta al abrir la página de autenticación de Twitter.
function getTwitterRequestAnswer()
{
if (xmlhttp.readyState == 4) {
var response = xmlhttp.responseText.split('&')
oauth_token = response[0].split('=')[1]
oauth_token_secret = response[1].split('=')[1]
oauth_callback_confirmed = response[2].split('=')[1]
var frame_url = 'https://api.twitter.com/oauth/authorize?oauth_token=' +
oauth_token + '&force_login=true'
window.open(frame_url)
}
}
La página de autenticación de Tweeter muestra un PIN que el usuario debe ingresar en la
pantalla principal del cliente. Una vez hecho eso, el usuario hace clic al botón de
Sign In que llama a signIn, que utiliza el pin para obtener la
señal de acceso autorizada.El manejo de la señal autorizada lo realiza el callback
getAccessToken.
Imagen 4: PIN de autenticación de Twitter
function signIn() {
var pinCode = document.getElementById('pinCode')
if (xmlhttp) {
xmlhttp.onreadystatechange = getAccessToken
var url = 'https://api.twitter.com/oauth/access_token'
initRequest('POST', url, [['oauth_verifier', pinCode.value]], {token:
oauth_token, secret: oauth_token_secret})
xmlhttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
xmlhttp.setRequestHeader('Accept-Language', 'en')
xmlhttp.send()
}
Una vez que la señal devuelta es extraída y almacenada en local storage, el código
llama a authenticationComplete, volviendo al camino que hubiera recorrido
de existir una señal previamente almacenada de una sesión anterior.
function getAccessToken() {
if (xmlhttp.readyState == 4) {
var text = xmlhttp.responseText
// Process errors
if (text.indexOf("?xml") != -1) {
if (text.indexOf("Invalid oauth_verifier parameter") != -1) {
var error = document.getElementById('errorStr')
error.innerHTML = 'Wrong PIN code. Please try again.'
return
}
}
var response = text.split('&')
user_oauth_token = response[0].split('=')[1]
user_oauth_token_secret = response[1].split('=')[1]
user_id = response[2].split('=')[1]
screen_name = response[3].split('=')[1]
if (typeof(localStorage) != 'undefined' ) {
localStorage.setItem('user_oauth_token', user_oauth_token)
localStorage.setItem('user_oauth_token_secret', user_oauth_token_secret)
console.log('user_oauth_token ' + user_oauth_token)
console.log('user_oauth_token_secret ' + user_oauth_token_secret)
}
authenticationComplete()
}
}
Esta función muestra la pantalla principal del cliente y agrega contenido al área
central a través de allMessage, que llama a los feeds de Twitter, analiza
y da formato a la respuesta (a través de getAllMessage y
parseAllMessage), para luego mostrar el resultado.
function authenticationComplete()
{
var html = '<div id="title"><b>Twitter
Client</b></div><nav><ul class="navigation"><li><a
class="button small white" href="#" onclick="retweetedByMe()">Retweeted By
Me</a></li><li><a class="button small white" href="#"
onclick="retweetedToMe()">Retweeted To Me</a></li><li><a
class="button small white" href="#" onclick="retweetsOfMe()">Retweets From
Me</a></li><li><a class="button small white" href="#"
onclick="AllMessage()">All Messages</a></li><li><a
class="button small white" href="#" onclick="logout
()">Logout</a></li></ul></nav><div
id="content"></div>'
var body = document.getElementById('bodyId')
body.innerHTML = html
allMessage()
}
function allMessage() {
if (xmlhttp) {
xmlhttp.onreadystatechange = getAllMessage
var url = 'https://api.twitter.com/1/statuses/home_timeline.json'
initRequest('GET', url, [], {token: user_oauth_token, secret:
user_oauth_token_secret})
xmlhttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
xmlhttp.setRequestHeader('Accept-Language', 'en')
xmlhttp.send()
}
}
function getAllMessage() {
if (xmlhttp.readyState == 4) {
var content= document.getElementById('content')
content.innerHTML = parseAllMessage(xmlhttp.responseText)
}
}
function parseAllMessage(response)
{
var obj = eval(response)
var result = ''
for (var i = 0; i < obj.length; i++) {
var text = processTextMessage(obj[i].text)
result += '<div class="stream-item" data-item-id="' + obj[i].id_str +
'">'
result += '<div class="stream-item-content tweet stream-tweet">'
result += '<div class="tweet-image">'
result += '<img height="48" width="48" src="' + obj
[i].user.profile_image_url + '">'
result += '</div>'
result += '<div class="tweet-content">'
result += '<div class="tweet-row">'
result += '<span class="tweet-user-name">'
result += '<span class="tweet-screen-name">' + obj
[i].user.screen_name + '</span> '
result += '<span class="tweet-full-name">' + obj
[i].user.name+ '</span>'
result += '</span>'
result += '</div>'
result += '<div class="tweet-row">'
result += '<div class="tweet-text">'
result += text
result += '</div>'
result += '</div>'
result += '<div class="tweet-row">'
result += '<br><small>' + (new Date(obj
[i].created_at)).toString() + '</small>'
result += '</div>'
result += '</div>'
result += '</div>'
result += '</div>'
}
return result
}
Para filtrar el feed de Twitter se llama a la correspondinente API. Los resultados son manejados de la misma forma que el feed completo.
La última funcionalidad, el "log out" simplemente borra la señal autenticada que estaba almacenada en local storage y cierra la aplicación. Si el programa se cierra sin llamar al logout la señal de autenticación permanecerá almacenada para usar la próxima vez que se utilice el cliente.
Resumen
El cliente de Twitter es una aplicación simple para mostrar tus feeds de Twitter. Demuestra el uso de xmlhttp para comunicar con un servicio remoto, la utilización de OAuth para autenticarse con ese servicio, callbacks para manejar comandos http completados y el uso de la facultad de local storage de HTML5 para almacenar información entre usos de la aplicación. Si bien son simples, los conceptos demostrados en este programa se pueden aplicar a una gran diversidad de situaciones.
Esto completa la quinta y última parte de la serie de Desarrollo de Aplicaciones en HTML5 para AppUp. Espero que lo hayan encontrado útil.
Me gustaría dar crédito a la ayuda de varios colegas de ICS en la creación de estos artículos. En particular mi agradecimiento va a Alexandr Makaryk y Denis Sapon que desarrollaron las aplicaciones de ejemplo, y a Dustin Kassman que colaboró con la escritura de estos artículos.
Copyright © 2011, Intel Corporation.
Brown Belt
Comentarios
Enviar nuevo comentario