ezakto code

Los contenidos de este blog están desactualizados.

Pero estoy pensando en actualizarlos y escribir más.

Si te interesa, dejame tu email (no spam, no newsletters). Si hay suficiente interés me pondré manos a la obra y te lo haré saber!


Tutorial React: Cloud backend con Firebase

27 de junio 2015

Añadiento almacenamiento en la nube y actualizaciones en tiempo real con Firebase

Firebase es un servicio que ofrece una plataforma en la nube para administrar el backend de nuestras aplicaciones. Soporta tanto aplicaciones web como móviles y la posibilidad de sincronizar el estado de los datos almacenados entre clientes en tiempo real. Tiene una API sencilla de utilizar y un plan gratuito que podemos usar para probar el servicio y, en este caso, desarrollar el aprendizaje.

Esta serie de tutoriales está enfocada en React y no en Firebase, por lo que no explicaré a fondo su API y funcionamiento. La idea es ilustrar las posibilidades.

Registro en Firebase

Lo primero será registrarnos en el plan gratuito en un sólo paso. Una vez registrados, deberíamos acceder al Dashboard de nuestra cuenta, donde tendremos una primera aplicación de prueba ya creada.

firebaseapp

En ella podemos ver una url, que corresponde a la url de nuestra base de datos en firebase. Nos servirá para interactuar con el servicio desde nuestra aplicación. Pero antes, debemos incluir su librería.

Vamos a editar el archivo index.html de la aplicación. Justo antes de incluir el archivo main.js, insertaremos la librería de firebase:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>React Keep</title>
    <link rel="stylesheet" href="css/style.css">
</head>
<body>
    <div id="app"></div>
    |||<script src="https://cdn.firebase.com/js/client/2.2.1/firebase.js"></script>|||
    <script src="js/main.js"></script>
</body>
</html>

Ya estamos listos para sincronizar datos. Una ventaja de haber implementado flux en la aplicación, es que será tremendamente fácil implementar la base de datos de firebase en reemplazo de la base de datos localStorage, ya que toda la sincronización de datos se produce en los action creators, sólo es necesario modificar ese archivo.

NoteActions.js

Las funciones loadDatabase() y saveDatabase() tenían la intención de simular la conexión y desconexión de una base de datos más compleja. Ahora que vamos a trabajar con una base de datos real con su propia API, estas funciones ya no serán necesarias. Así mismo, los métodos que en su mayor parte interactuaban con esta base de datos quedan obsoletos, así que directamente eliminamos todo el contenido del archivo y lo reescribiremos.

Veamos como es el nuevo código y luego explicaremos los conceptos nuevos:

var AppDispatcher = require('../dispatcher/AppDispatcher');

// Creamos una referencia a un nodo "notes" en el almacenamiento firebase
var NotesRef = new Firebase('https://url-de-nuestra-base-de-datos.firebaseio.com/notes');

var NoteActions = {

    readNotes: function() {
        // Escuchamos el evento "child_added", que se ejecutará cada vez
        // que se agregue un elemento al nodo
        NotesRef.on('child_added', function(snapshot) {
            // Extraemos la información obtenida
            var note = snapshot.val();

            // Usamos como id su key única en el almacenamiento
            note.id = snapshot.key();

            // Enviamos como mensaje al dispatcher la nota agregada
            AppDispatcher.dispatch({
                type: 'CREATE',
                note: note
            });
        });

        // Esuchamos el evento "child_removed", que es el inverso al anterior,
        // pues se ejecutará cada vez que un elemento sea eliminado del nodo
        NotesRef.on('child_removed', function(snapshot) {
            // Obtenemos la key única del elemento que se eliminó, que usamos como id
            var id = snapshot.key();

            // Enviamos al Dispatcher la id de la nota eliminada
            AppDispatcher.dispatch({
                type: 'DELETE',
                id: id
            });
        });
    },

    createNote: function(title, text) {
        // Insertamos la nota en el nodo
        NotesRef.push({
            title: title,
            text: text
        });
    },

    deleteNote: function(id) {
        // Accedemos al elemento y lo eliminamos
        NotesRef.child(id).set(null);
    }

}

module.exports = NoteActions;

La instancia NotesRef es una referencia a un nodo en el almacén de datos de nuestra aplicación en Firebase. Esta referencia es, además, un EventEmitter tal como nuestras stores. Por lo que puede ejecutar callbacks cada vez que ciertos acontecimientos ocurran.

Lo que hacemos en readNotes() es asignar listeners a dos eventos en particular. Primero child_added, que se ejecutará cada vez que un elemento sea añadido, y además se ejecutará una vez por cada elemento existente la primera vez que nos conectemos, por lo que el simple hecho de escucharlo será suficiente para cargar las notas almacenadas inicialmente. Al callback se le pasará como argumento un snapshot (imagen del estado actual de los datos al momento de emitirse el evento). Con el método val() del snapshot, obtenemos un objeto JavaScript que representa los datos contenidos. Cada vez que un elemento es insertado con push() (usado un poco más abajo), Firebase le asignará una key única en el almacenamiento, que nosotros usaremos como id en nuestra aplicación. La obtenemos con snapshot.key(). Finalmente enviamos al Dispatcher el valor almacenado.

Por lo tanto, el nuevo readNote() sólo consiste en empezar a escuchar eventos. Firebase hará el resto.

createNote() hace uso del método push(). Este método inserta un elemento en la lista de elementos hijos del nodo, y, como ya mencioné, le asigna un key único. Cada vez que push() es ejecutado, se envía la información a Firebase que, a su vez, notificará la inserción con el evento child_added que empezamos a escuchar antes, por lo que automáticamente se generará el action.

deleteNote() es más sencillo aún. Usando child() obtenemos una referencia a un elemento hijo del nodo, y usando set(null) lo eliminamos. Firebase disparará el evento child_removed automáticamente, que empezamos a escuchar antes, por lo que se generará el action.

Como la interfaz de los métodos es la misma (nombres y argumentos), y producen el mismo resultado (envían los mismos mensajes al Dispatcher), no es necesario modificar nada en el resto de la aplicación. Y si en algún momento decidimos cambiar firebase por algún API REST, o cualquier otro método de almacenamiento, el proceso debería ser el mismo.

Una de las cosas interesantes de firebase es que sincroniza los datos en todos los clientes instantáneamente. Por lo que si abrimos la aplicación en dos navegadores diferentes, los cambios hechos es uno se reflejarán en el otro instantáneamente.

Para que la aplicación alcanzara un nivel más serío, habría que modificar los permisos de lectura y escritura de firebase, implementar autenticación, etc. Pero son temas que van más allá de este tutorial introductorio.

Eso es todo, amigos!