Cloud Functions for Firebase: Utilizando los activadores de Firebase Storage

Cloud Functions for Firebase Functions es una de las caracter铆sticas que m谩s me emocionan sobre la plataforma de Firebase. Si no sabes que son las Firebase Cloud Functions, puedes ver 茅ste post que Carlos ya ha escrito.

Hola a todos! Soy Carlos Rojas (@carlosrojas_o) y voy a ser su guia el dia de hoy en como utilizar los activadores del Storage con Firebase Functions.

驴Qu茅 vamos hacer?

Vamos a crear el siguiente flujo. Cuando una imagen sea subida a Firebase Storage va a realizar lo siguiente.

  1. Va a convertir las im谩genes que no sean JPG a este formato.

Algo muy 煤til y muy com煤n en la actualidad con todas las apps de im谩genes.

Preparaci贸n

Ok, para utilizar estas caracter铆sticas y en general Firebase, debes tener lo siguiente instalado.

  1. NodeJS.

  2. Firebase Tools. Para esto desde un terminal ejecuta.

    $ npm install -g firebase-tools

  3. Debemos comenzar un proyecto en la consola web de Firebase. Debes crear una cuenta desde aqu铆. y luego comenzar un proyecto.

  4. Una vez creamos el proyecto, volvemos a nuestra terminal y ejecutamos el siguiente comando desde la carpeta de nuestro proyecto:

    $firebase init functions

  5. Listo, ya debemos tener nuestro proyecto listo y conectado.

Consideraciones

Firebase Functions es una caracter铆stica muy poderosa ya que nos da el poder de computaci贸n del Backend solo creando peque帽as funciones. Pero para utilizarlo correctamente debemos tener claro algunas cosas.

  • Las funciones se escriben con NodeJS.
  • El API de la librer铆a de functions es muy poderoso, 茅chale un vistazo para saber c贸mo te puede ayudar aqu铆.

Continuemos

Hasta este punto deber铆as tener algo as铆.

Screen-Shot-2017-09-20-at-20.25.59

Lo importante ac谩, es que vamos a trabajar sobre el archivo index.js en la carpeta functions.

Vamos al c贸digo

Primero debemos importar los m贸dulos que vamos a utilizar.

'use strict';

const functions = require('firebase-functions');
const mkdirp = require('mkdirp-promise');
const gcs = require('@google-cloud/storage')();
const spawn = require('child-process-promise').spawn;
const path = require('path');
const os = require('os');
const fs = require('fs');

// File extension for the created PNG files.
const PNG_EXTENSION = '.png;

Aca es importante ver que estamos utilizando modulos adicionales para el trabajo y por lo tanto debemos agregarlo a nuestro proyecto en la carpeta /functions.

Agrego aca la lista:

Nota: debes instalar cada requerimiento con npm install, mira el link para hacerlo.

Ya con esto listo creamos nuestra funci贸n.

exports.imageToPNG = functions.storage.object().onChange(event => {

    const object = event.data;
    const filePath = object.name;
    const baseFileName = path.basename(filePath, path.extname(filePath));
    const fileDir = path.dirname(filePath);
    const PNGFilePath = path.normalize(path.format({dir: fileDir, name: baseFileName, ext: PNG_EXTENSION}));
    const tempLocalFile = path.join(os.tmpdir(), filePath);
    const tempLocalDir = path.dirname(tempLocalFile);
    const tempLocalPNGFile = path.join(os.tmpdir(), PNGFilePath);
  
    // Verifica si el elemento subido al Storage es una imagen.
    if (!object.contentType.startsWith('image/')) {
      console.log('No es imagen.');
      return;
    }
  
    // Verifica si la imagen ya es un PNG.
    if (object.contentType.startsWith('image/png')){
      console.log('Es un PNG.');
      return;
    }
  
    // El evento se activo por un borrado o movida del elemento.
    if (object.resourceState === 'not_exists') {
      console.log('El elemento fue borrado.');
      return;
    }
  
    const bucket = gcs.bucket(object.bucket);
    // Crea una ruta temporal donde el archivo sera guardado temporalmente.
    return mkdirp(tempLocalDir).then(() => {
      // Descarga un archivo desde el bucket.
      return bucket.file(filePath).download({destination: tempLocalFile});
    }).then(() => {
      console.log('El archivo ha sido descargado a',
          tempLocalFile);
      // convierte la imagen a PNG usando ImageMagic
      return spawn('convert', [tempLocalFile, tempLocalPNGFile]);
    }).then(() => {
      console.log('La imagen en PNG ha sido creada ', tempLocalPNGFile);
      // Subiendo la imagen PNG
      return bucket.upload(tempLocalPNGFile, {destination: PNGFilePath});
    }).then(() => {
      console.log('imagen nueva subida a ', PNGFilePath);
      // Liberamos el espacio de los archivos temporales.
      fs.unlinkSync(tempLocalPNGFile);
      fs.unlinkSync(tempLocalFile);
    });
  });

Analicemos varias cosas.

Primero el uso de functions.storage.object().onChange() para escuchar los eventos que se realicen sobre el storage.

El uso de const gcs = require('@google-cloud/storage')(); para descargar la imagen en el storage y convertirla con ImageMagick.

El resto del codigo creo que se explica por si mismo, realizamos las verificaciones pertinentes y si cumple el requerimiento ( Ser imagen y no estar en PNG ) realizamos la operaci贸n.

Despliegue en Firebase

Ahora que ya tenemos nuestra funci贸n lista, simplemente realizamos el despliegue. En este punto puedes usar dos enfoques.

$ firebase deploy

este comando te envia todo (Firebase Hosting, Functions, etc ) a firebase, para este ejemplo no deberias sentir la diferencia, pero si tienen una app robusta en hosting, si se demorara mucho en actualizar tus funciones. Para solucionar esto, el segundo enfoque es.

$ firebase deploy --only functions

este comando solo actualizar谩 las funciones.

Verificaci贸n y depuraci贸n.

Para probar nuestras funciones es muy simple, solo ingresa a la consola web de Firebase y sube una imagen en JPG.

Screen-Shot-2017-09-20-at-20.30.23

Screen-Shot-2017-09-20-at-20.30.31

y despu茅s de unos segundos debe aparecer la nueva imagen.

Screen-Shot-2017-09-20-at-20.30.38

Perfecto.

Puedes ver los mensajes de consola que colocamos en la funci贸n en la consola web de firebase en Functions.

Screen-Shot-2017-09-20-at-20.31.23

Screen-Shot-2017-09-20-at-20.31.32

Pr贸ximos pasos

  • Ingresa a la documentaci贸n e intenta agregar otros activadores a tu c贸digo.
  • Aprende un poco de los fundamentos de Node, te ser谩n de utilidad en este servicio.

Bueno espero que este tutorial sea de ayuda en sus proyectos y se sientan tan emocionados como yo sobre esto. Si tienen preguntas mi twitter es 茅ste y los invit贸 a la comunidad de Ionic en espa帽ol ion-book donde pas贸 la mayor铆a de mi tiempo. Muchas gracias por la oportunidad de escribir en este blog y espero hacerlo en otra oportunidad. Hasta Pronto :)


驴Quieres contactar conmigo personalmente? Puedes hacerlo por email a trav茅s de Earn.com. Tiene asociado un coste de $20, qu茅 s贸lo se te cobrar谩 cuando responda.

Desarrollador web Frontend y apasionado de JavaScript. Aqu铆 te ense帽o todo lo que aprendo y conozco sobre JavaScript y la programaci贸n web en general.

驴Te gusta lo que lees?
Ap煤ntate a mi bolet铆n, newsletter, lista de correo o como quieras llamarlo. S贸lamente env铆o 1 email al mes con lo m谩s relevante. 驴Te apuntas?