Introducción a Firebase Storage

  • Por
Explicamos todo lo que debes saber para comenzar con el servicio Storage de Firebase, junto con un ejemplo sencillo para hacer el upload, operación put, desde una página web.

En la nueva versión de Firebase uno de los servicios estrella es el de "Storage" que nos permite subir archivos a la nube y compartirlos entre usuarios de la aplicación. Era una de las demandas más comunes por parte de los desarrolladores en Firebase que afortunadamente ya tenemos con nosotros. Gracias a ello, tanto desde la web como desde dispositivos somos ahora capaces de cargar y manipular archivos, sin tener que escribir código de la parte del backend.

Firebase Storage funciona usando el servicio Google Cloud Storage por debajo. Existe un depósito de almacenamiento, llamado "bucket" donde podemos enviar datos que estarán asociados a nuestra aplicación. Sin embargo, nosotros no interactuaremos directamente con Google Storage, sino que usaremos el SDK que nos ofrece una operativa simplificada y muy similar a la que ya manejamos cuando escribimos datos en la base de datos en tiempo real.

En resumen, Firebase es una envoltura del servicio de almacenamiento de Google, beneficiándose de varias ventajas y potencia de la nube de Google y manteniendo un código sencillo y enteramente del lado del cliente. Además gracias a la integración del servicio de almacenamiento de Firebase podemos crear reglas de seguridad que usen los datos y usuarios de nuestra aplicación, de modo que podemos mantener los archivos de cada persona privados o bien compartirlos con otros usuarios que se desee.

En este artículo del Manual de Firebase queremos dar una pequeña introducción al servicio de Storage y ofrecer un primer script con el que podrás probarlo.

Cómo está organizado el servicio de storage

El almacenamiento en la nube que nos ofrece Firebase está organizado en una estructura jerárquica, igual que las carpetas en un disco duro normal, o los datos en la "Realtime Database". También usamos el carácter "/" para separar los niveles, igual que en referencias de la base de datos o carpetas del disco.

carpeta/carpeta/archivo.png

Para navegar por las carpetas existen unos métodos específicos, que para facilitarnos la vida nos sonarán mucho a los que ya estamos familiarizados con el sistema de acceso a los datos en tiempo real.

Del lado de Javascript tenemos que comenzar accediendo al servicio donde se encuentra el API de Storage.

var storageService = firebase.storage();

Una vez tenemos nuestro servicio, podemos acceder a toda la serie de funciones que se encuentran en él. El paso que generalmente realizarás a continuación es enlazar con una referencia. Puedes entender una referencia como una ruta dentro del sistema de almacenamiento, como una ruta en el sistema de base de datos o una ruta a un archivo de tu disco duro.

var referencia = storageService.ref('ruta/a/un/lugar/de/almacenamiento');

Otra alternativa sería obtener una referencia raíz y luego con el método child() navegar a una referencia interior.

var referencia = storageService.ref();
var referencia = referencia.child('images');

Subir un archivo a Storage Firebase

Subir un archivo es tan sencillo como, partiendo de una referencia, invocar el método put() que se encargará de realizar todo el trabajo por nosotros. Este método recibe dos parámetros, el propio archivo a subir y un objeto con metadatos. El parámetro de metadatos es opcional pero esencial para implementar mecanismos importantes con respecto al tratamiento de archivos.

El método nos devuelve un objeto de la clase "UploadTask" (firebase.storage.UploadTask) con el que podemos monitorizar el estado del upload del archivo mediante eventos que explicaremos en el punto siguiente de este artículo, así como realizar acciones como cancelar una subida de archivo.

var uploadTask = referencia.put(file, metadata);

Nota: La parte de obtener ese archivo ("Blob" o "File") mediante el navegador ya es otro asunto y lo puedes hacer con APIs HTML5. El API File permite acceder a archivos del disco duro del usuario, que haya seleccionado mediante un campo INPUT type file. El API Blob básicamente permite crear objetos con datos generados desde Javascript, es decir, que no necesariamente corresponden con archivos que tengas en tu disco duro. Veremos un ejemplo más tarde.

Suscribirse a eventos relacionados con la carga de archivos

Igual que hay eventos que tienen que ver con la autenticación, el SDK de Firebase implementa eventos que se disparan cuando ocurren cosas que tienen que ver con la parte de almacenamiento.

El evento "state_changed" lo podemos gestionar a partir del objeto de la clase UploadTask que hemos recibido como respuesta a una operación put(). Es el que nos permite suscribirnos a cambios de estado del proceso de upload del archivo.

Este evento se invoca con el método on() sobre el objeto de la clase UploadTask, al que se le tienen que indicar varios parámetros.

  • El evento, "state_changed"
  • La función callback "Next": que permite hacer cosas durante la carga. Es como un "observer" que se invoca repetidas veces y en el que somos capaces de obtener datos como podría ser el porcentaje de subida del archivo o el estado del upload. Si no se quiere definir ese observador se puede enviar simplemente un null.
  • La función callback "Error": que es como cualquier error de Firebase y será invocada en caso que la carga del archivo falle.
  • La función callback "Complete": que se invocará cuando la carga del archivo haya terminado.

uploadTask.on('state_changed', null, function(error){
  console.log("Se ha producido un error:, ", error);
}, function() {
  console.log("Carga del archivo completada");
});

Como puedes ver, hemos enviado como función "Next" el valor null, porque no queremos monitorizar el estado de la carga durante el tiempo de carga. Luego tenemos las dos funciones para detectar posibles errores y la carga completada.

El "snapshot" de un proceso de carga

Durante el proceso de carga de un archivo, y una vez que ya ha terminado este proceso, podemos acceder a una instantánea del estado del upload o al resultado final de la carga. A partir del snapshot podemos obtener información diversa, como por ejemplo el estado actual, los bytes transferidos, o la URL donde quedó ese archivo en la nube.

El snapshot pertenece también al objeto de la clase UploadTask y podemos acceder a él de la siguiente manera. No vamos a ver todas las posibilidades ahora, pero sí algunas básicas:

  • uploadTask.snapshot.totalBytes: Los bytes totales del archivo a ser enviados para su carga.
  • uploadTask.snapshot.bytesTransferred: Los bytes transferidos hasta un instante dado.
  • uploadTask.snapshot.state: El estado actual de la subida.
  • uploadTask.snapshot.downloadURL: una cadena la dirección donde está disponible ese archivo en la nube.

Ejercicio completo de upload de un archivo a Firebase

Ahora vamos a irnos a la parte práctica y veremos un código completo que realiza las funciones de upload de un archivo. Pero antes debes saber que de manera predeterminada Firebase exige que para subir archivos deba haberse autenticado el usuario mediante cualquiera de los mecanismos. En este ejemplo usaremos autenticación anónima, pero ten en cuenta que debe estar habilitada en la consola de Firebase.

Ten en cuenta también que tendrás que colocar tus propios datos de aplicación Firebase para que funcione. Explicamos cómo obtener tus datos de inicialización de Firebase en el artículo sobre Introducción a Firebase 3.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Subir archivos con Firebase</title>
</head>
<body>
  <input type="file" id="campoarchivo">
  <div id="mensaje"></div>

  <script src="https://www.gstatic.com/firebasejs/live/3.0/firebase.js"></script>
  <script>
    // Initialize Firebase
    var config = {
      apiKey: "AIzaSyAKAAAPi-aPffdsliTggEtTW23s222I371Y",
      authDomain: "tuapp.firebaseapp.com",
      databaseURL: "https://tuapp.firebaseio.com",
      storageBucket: "tuapp.appspot.com",
    };
    firebase.initializeApp(config);

    // Servicios de APIs Firebase
    var authService = firebase.auth();
    var storageService = firebase.storage();

    window.onload = function() {
      // realizamos la autenticación anónima (debe estar activada en la consola de Firebase)
      authService.signInAnonymously()
        .catch(function(error) {
          console.error('Detectado error de autenticación', error);
        });

      // asociamos el manejador de eventos sobre el INPUT FILE
      document.getElementById('campoarchivo').addEventListener('change', function(evento){
        evento.preventDefault();
        var archivo  = evento.target.files[0];
        subirArchivo(archivo);
      });
    }

    // función que se encargará de subir el archivo
    function subirArchivo(archivo) {
      // creo una referencia al lugar donde guardaremos el archivo
      var refStorage = storageService.ref('micarpeta').child(archivo.name);
      // Comienzo la tarea de upload
      var uploadTask = refStorage.put(archivo);

      // defino un evento para saber qué pasa con ese upload iniciado
      uploadTask.on('state_changed', null,
        function(error){
          console.log('Error al subir el archivo', error);
        },
        function(){
          console.log('Subida completada');
          mensajeFinalizado(uploadTask.snapshot.downloadURL, uploadTask.snapshot.totalBytes);
        }
      );
    }

    // a esta función la invocamos para mostrar el mensaje final después del upload
    function mensajeFinalizado(url, bytes) {
      var elMensaje = document.getElementById('mensaje');
      var textoMensaje = '<p>Subido el archivo!';
      textoMensaje += '<br>Bytes subidos: ' + bytes;
      textoMensaje += '<br><a href="' + url + '">Ver el fichero</a></p>';
      elMensaje.innerHTML = textoMensaje;
    }
  </script>
</body>
</html>

Hemos comentado el código para que no te pierdas. Estamos seguros que después de la lectura del artículo y los comentarios eres capaz de identificar toda la operativa de carga de un fichero a Firebase. Si lo pruebas solo ten en cuenta colocar tus propios datos de inicialización de Firebase.

Es un script de carga simplificado lo suficiente para que sea sencillo de entender. En otros artículos lo editaremos para hacerlo un poco más sofisticado y que sea capaz de mostrarnos el progreso de una subida, algo muy importante para las cargas de archivos grandes.

Autor

Miguel Angel Alvarez

Miguel es fundador de DesarrolloWeb.com y la plataforma de formación online EscuelaIT. Comenzó en el mundo del desarrollo web en el año 1997, transformando su hobby en su trabajo.

Compartir

Comentarios

ronald948

28/6/2016
Muy bueno!
Interesante el articulo

gracias!

Alonso

01/7/2016
Mucho q aprender con Firebase
El servicio es muy completo estoy aprendiendo Firebase con vosotros para una app que quiero desarrollar

Ricardo

05/7/2016
Firebase Storage + AngularJs
Esta muy padre este articulo, pero tengo una duda tengo un formulario con bootstrap y aungular como integro esta función y que en objeto urlimg aparezca la url de la imagen.

midesweb

29/7/2016
firebase con angularjs
Ricardo, lo mejor es que explores las características de "angularfire" que es la librería para trabajar con Angular desde Firebase. Tengo entendido que hay providers para que puedas hacer la operativa de trabajo con el storage de Firebase con el flujo habitual de desarrollo de aplicaciones Angular.

Cristian Eriza

13/9/2016
duda
Hola sabes me funciona perfecto y lo envia a firebase pero no se porque no puedo obtener la url no me muestra nada si pongo un alert tampoco me funciona.

Antonio

13/11/2016
AngularFire no incluye el servicio de storage
Sólo la versión de angularFire2 incluye el servicio de storage y no es compatible con Angularjs, sino que sólo existe para Angula 2.
¿Hay alguna manera de integrar el servicio de storage en angularjs sin hacer uso de la librería angularfire?

midesweb

27/1/2017
Para Angular 1
Si usas Angular 1 siempre puedes montártelo con Javascript directamente, no es difícil. Hasta ahora es lo que vengo haciendo yo con Polymerfire, que no tiene integración todavía con la parte de storage y bueno, te puedes hacer tus componentes que usan el Javascript "vanilla" para enviar datos al storage.