Cómo usar un servidor web en Node.js para crear un comando en Slack

Si ya hablamos en este blog de cómo funcionan los comandos de Slack, cómo crearlos y cómo darle el formato deseado a los mensajes que enviemos, en el post de hoy explicaremos cómo tener funcionando un comando personalizado de Slack en nuestro equipo.

logo_slack

Sabemos que tenemos que devolver JSON en un endpoint determinado, así que lo más fácil es hacer un simple backend con NodeJS. Usaremos el framework Loopback, basado en Express.js. Habrá mejores y peores alternativas, pero en mi caso tenía ganas de probarlo.

Acerca de Loopback

Loopback se basa en Express y está enfocado en la rápida construcción de APIs escalables. A través de su CLI puedes tener un proyecto funcional de Loopback en solo dos comandos. A través de definiciones de modelo en ficheros JSON se puede conectar fácilmente con datos de Oracle, SQL Server, MongoDB o MySQL. Incluso provee de un ORM para las relaciones entre modelos.

Está diseñado para cumplir desde el principio las mejores prácticas en el diseño de APIs. Integra desde el inicio Swagger 2.0 para que puedas debugguear desde el inicio fácilmente tus APIs.

Provee de diferentes tipos de autenticación desde el inicio, incluyendo sociales como Facebook, Google, Twitter o Github a través de Passport.

Lógica del comando /meme

La idea tras el comando creado es que, cuando se ejecute, devuelva un mensaje con la imagen de un meme. En nuestro caso descargaremos y parsearemos la URL de un blog con este tipo de contenidos y conseguiremos la primera imagen del primer post disponible. De esta forma, como el blog se actualiza constantemente, cada cierto tiempo tendremos contenido nuevo.

Preparación del proyecto

Para tenerlo todo preparado:

  • Instala NodeJS. Es la plataforma que usaremos para todo nuestro servidor web.
  • Instala Loopback. Debería bastar con: npm install -g strongloop. Loopback es el framework, basado sobre NodeJS sobre el que construiremos nuestro código. Es posible que tengas que revisar que tienes permisos de escritura sobre /usr/local/lib/node_modules y /usr/local/bin.

El flag -g instala el paquete a nivel de sistema operativo. Esto es especialmente útil para hacer uso de las herramientas de Loopback como la creación de proyectos.

Antes de empezar, recomiendo que todo se haga bajo un repositorio de Git (en Bitbucket puedes tener uno privado y totalmente gratis).

Ahora ya podemos crear nuestro nuevo proyecto Loopback. En una shell, en el directorio que queramos (el del repo si lo hemos creado), ejecutamos: slc loopback.

slack_1

En nuestro caso hemos seleccionado como plantilla inicial un hello-world, ya que contiene una vista de prueba que usaremos de guía para nuestro desarrollo.

Esto creará un proyecto completo de Loopback listo para ser levantado con node. El proyecto ya tendrá un package.json que tiene los metadatos del proyecto npm. Entre estos datos están todas las dependencias, versión, URL del proyecto, licencia… Gracias a esto, cualquiera podría instalarlo con un simple npm install en el directorio donde se encuentre el package.json.

Abre el proyecto con tu editor favorito y observa que se han creado varios ficheros relativos al servidor y a su configuración, así como un modelo llamado note. Podemos editar este modelo ya creado automáticamente, pero vamos a crear uno nuevo ejecutando slc loopback:model, luego ejecutaremos slc loopback:remote-method para añadirle un nuevo endpoint que implementará la funcionalidad que queremos.

slack_2

Configurar el endpoint

Recapitulando, ya tenemos nuestro servidor web con el enpdoint /api/commands/meme listo para implementar funcionalidad. La respuesta que tenemos que dar al server de Slack es algo así:

{
  "response_type": "in_channel",
  "attachments": [
    {
      "title": "De tu envidia nace mi fama\n",
      "title_link": "http://yonkiblog.com/de-tu-envidia-nase-mi-fama/",
      "image_url": 
"http://41.media.tumblr.com/c27a5fd05e908f94d457ea3331339e89/tumblr_o5rumzl0t21slstjgo4_500.jpg",
      "color": "#764FA5"
    }
  ]
}

Para devolver JSON desde la propia vista hay que modificar la definición del modelo command (command.json) y en nuestro endpoint meme, definir qué se devolverá un solo objeto. Para ello en returns, se cambia [] por {“root”: true, “type”: “object”}

Ya tenemos todo lo necesario para implementar la solución. Para parsear el blog, he usado un paquete npm llamado jsdom. Es una librería que nos servirá para descargar la página del blog y manejar el contenido scrappeando la web a través de jQuery. Si quieres instalarlo y a la vez añadirlo a la lista de requirements del package.json, instálalo con npm install jsdom –save.

El código que se ha implementado es tremendamente sencillo:

module.exports = function(Command) {
  /**
   * Get the latests image of blog
   * @param {Function(Error)} callback
   */

  Command.meme = function(callback) {
    var jsdom = require("jsdom");

    jsdom.env(
      "http://yonkiblog.com/category/humor/",
      ["http://code.jquery.com/jquery.js"],
      function (err, window) {
        if (err){
          console.log(err);
        } else {
          console.log("Successfully downloaded humor category");
        }
        var $ = window.$;
        var image_url = $(".entry-content img")[0].src;
        var response = {
          response_type: 'in_channel',
          text: "Ni pizca de gracia:\n<" + $(".entry-title a")[0].href + "|" + $(".entry-title a")[0].text + ">",
          attachments: [{
              image_url: image_url,
              thumb_url: image_url,
              author_name: 'Yonkiblog'
          }]
        };

        callback(null, response);
      }
    );
  };
};

Descargamos la web, la renderizamos (jQuery incluido) y devolvemos un JSON como el que necesita Slack para mostrar el mensaje al usuario. Este mensaje contendrá un link al artículo, el título y la primera imagen.

Una vez que tenemos el objeto response listo, invocamos a callback con este objeto como segundo parámetro. De esta forma, solo devolvemos una respuesta desde el servidor cuando la tenemos lista. La descarga de la web es asíncrona, no bloqueante. La respuesta que damos nosotros por parte del servidor también es asíncrona, es la magia de Node.js.

Ya tenemos todo listo, para levantar el servidor simplemente ejecutamos en el directorio del proyecto: node.

Arrancará el servidor web en local bajo el puerto 3000 (configurable vía server/config.json).

Loopback te da automáticamente Swagger para el proyecto, un explorador de recursos para que puedas trastear con tu API. Para verlo accede a localhost:3000/explorer.

slack_3

Haciendo visible nuestro servidor

Ahora para hacerlo visible desde Internet, usaremos Ngrok. Ngrok expone un servidor en local a través de una URL visible al resto de Internet. De esta forma nuestro servidor local, aunque esté bajo un NAT, firewall y demás, podrá ser accedido desde fuera de la red local.

Una vez descargado, como queremos exponer el puerto 3000 local, ejecutamos en una shell: ./ngrok http 3001

slack_4

El subdominio que nos han dado es https://9339a566.ngrok.io. Así que en nuestro caso, el endpoint meme estará en https://9339a566.ngrok.io/api/commands/meme. Configuramos esta URL en el comando de Slack que ya creamos y… ¡ya está listo para usarse!

slack_5

Si te interesa, el proyecto está en Github: https://github.com/IvanAlegre/SlashMemeCommand

Recibe más artículos como este

Recibirás un email por cada nuevo artículo.. Acepto los términos legales

Escribe un comentario