Desarrollo de aplicaciones en HTML5 para AppUp - Parte 5: Una aplicación cliente de Twitter

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.


Twitter Client Main Screen
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:

  1. Solicitar señal de acceso a Twitter
  2. Twitter devuelve señal de acceso desautorizada
  3. El cliente redirecciona a la página de autorización de Twitter.
  4. El usuario da el OK para que el cliente acceda a su cuenta
  5. La página de autorización de Twitter solicita un PIN
  6. El usuario introduce el PIN en el cliente
  7. El cliente usa el PIN para obtener señal de acceso autorizada
  8. 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.



Twitter Client Main Screen When Unauthenticated
Imagen 2: Pantalla principal del cliente cuando no hubo autenticación



Twitter Authentication Screen
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()
    }
}
Transcripción 2: Función twitterRequest del archivo index.js

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)
    }
}
Transcripción 3: Función getTwitterRequestAnswer del archivo index.js

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.



Twitter Authentication PIN
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()
    }
Transcripción 4: Función signIn del archivo index.js

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()
    }
}
Transcripción 5: Función getAccessToken del archivo index.js

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()
}
Transcripción 6: Función authenticationComplete del archivo index.js

 

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()
    }
}
Transcripción 7: Función allMessage del archivo index.js

 

function getAllMessage() {
    if (xmlhttp.readyState == 4) {
        var content= document.getElementById('content')
        content.innerHTML = parseAllMessage(xmlhttp.responseText)
    }
}
Transcripción 8: Funciónn getAllMessage del archivo index.js



 

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
}
Transcripción 9: Función parseAllMessage del archivo index.js

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.
0
2Kvistas

Comentarios

Enviar nuevo comentario

The content of this field is kept private and will not be shown publicly.