lunes, 3 de abril de 2017

Api Gateway , multipart/form-data parser. Multi File Uploader.

El siguiente es un video tutorial que muestra los pasos a seguir para poder crear un Api en Amazon ApiGateway que procesa el POST enviado por un formulario que trae archivos (texto o binario).

El formulario envía datos usando: "multipart/form-data". El contenido "multipart" implica que todos los archivos seleccionados desde el formulario vendrán uno junto al otro separados por un elemento llamado "boundary" (que es creado y enviado también por el cliente Http en sus headers).

Para poder procesar el contenido multipart/form-data es necesario de una herramienta que he creado y publicado en los paquetes NPM, a continuación:

https://www.npmjs.com/package/parse-multipart

La necesidad que me llevó a crear el paquete es la propia naturaleza de Api Gateway y la falta de disponibilidad o exceso de complicación de otras herramientas existentes, estas ultimas mejor orientadas a servir esquemas tradicionales, es decir, sus autores las han creado para automatizar lo mas que se pueda el proceso desde el lado del servidor para el payload enviado. Este exceso de automatización es bueno para esos casos normales donde se usan servidores dedicados a servir el request, pero para el caso de Api Gateway son relativamente complicados de implementar o requiren de dependencias. El paquete "parse-multipart" en cambio (enlace arriba) es simple, es una sola maquina de estado finito capaz de leer el contenido crudo del payload y entregar un array con los archivos obtenidos de el.

En el video a continuación describo cinco pasos claros (descritos en el video), el codigo al que se hace referencia en el video lo dejo acá:

form.html, un formulario que corre en algun servidor http y que envia el POST al api gateway.

<html>
<h1>
ApiGateway: File Uploading Example</h1>
<form action="https://voceeedzwf.execute-api.us-west-2.amazonaws.com/test/uploader" enctype="multipart/form-data" method="POST">

<input multiple="" name="your-files" type="file" />

<input type="submit" value="Submit" />
</form>
</html>


package.json, usado para poder importar el paquete "parse-multipart"

{
  "name": "lambda",
  "version": "1.0.0",
  "description": "sample tutorial",
  "main": "index.js",
  "dependencies" : { 
   "parse-multipart" : "*" 
  },
  "author": "Cristian Salazar  (https://plus.google.com/+ChristianSalazar)",
  "license": "ISC"
}

index.js El código de la función lambda.

// see also: https://www.npmjs.com/package/parse-multipart
var multipart = require("parse-multipart");

// "exports.handler" must match the entrypoint defined in the lambda Config.
exports.handler = function(event,context,callback){
 var bodyBuffer = new Buffer(event['body-json'].toString(),'base64');
 var boundary = multipart.getBoundary(event.params.header['content-type']);

 var parts = multipart.Parse(bodyBuffer,boundary);
 
 callback(null,{ result : 'SUCCESS' , files : parts });
}


A continuación el video:




















miércoles, 22 de marzo de 2017

Microservices y ApiGateways. Un Ejemplo.

Los microservices son funciones que realizan una tarea específica. Son ejecutadas tras algún evento (por ejemplo un cambio en un registro de una base de datos) o por la invocación a una URL o Endpoint, esta última controlada o gestionada por una Api Gateway.

En primer lugar te pediré que olvides lo que sabes de LAMP, WAMP, Hosting, VPC y similares entornos en donde antes desarrollabas tu aplicación web, la cual era dependiente de todo un entorno de software que tú debias crear (Instalar el sistema operativo,  actualizar paquetes, crear un loadbalancer, cuidar la cache y finalmente instalar un servidor http). Todo ese proceso proveerá un sistema monolítico en la mayoría de los casos.

Los Microservices llevan al desarrollador al siguiente nivel de desarrollo distribuido, realmente en la nube.

Hay dos conceptos clave que debes comprender:

1) Microservices. 


Son funciones que reciben argumentos mediante alguna via, realizan una tarea y crean un resultado que otras piezas o funciones pueden ver.  Por ejemplo, en Amazon AWS existe la base de datos DynamoDB, la cual puede integrarse con Funciones Lambda (Los microservices de Amazon), de modo que cuando un registro de la base de datos se actualiza o se inserta entonces una función se ejecuta y hace algo al respecto, por ejemplo, enviar un email, un mensaje de texto, una inserción en otra tabla etc.   Otro ejemplo es cuando una función se ejecuta mediante una llamada a una Url a través del uso de una ApiGateway y entonces esta función devolverá algo (contenido Json, Html, una imagen, procesará un POST, etc).

Como ejemplos de Microservices tenemos:

1.1) Lambda Functions de Amazon
1.2) Funciones de Google Cloud
1.3) Azure Functions (Windows)


2) ApiGateway (o Endpoints)


Un ApiGateway provee una URL que será manejada por una función (Un microservice) u otra Api Restul. En términos simples, un ApiGateway permite tener una Url para ejecutar un servicio dependiendo de: Parametros entregados en la Url o mediante Headers, principalmente el Content-Type.  Por ejemplo, según el Content-Type una Api podria filtrar el cuerpo del request para pasarle a la función que se ejecuta solo aquello que deba recibir, igualmente podria filtrar la respuesta y entregarla en un formato específico.

Un ApiGateway puede ser considerada una fachada (Facade) y también un Proxy entre una función y un cliente que la invoca.

Puede verse como "el cable" que une un browser con una función. El ApiGateway también sirve como "mapeador" de argumentos lo cual la hace muy útil ya que permite que podamos usar una misma función para responder a diferentes tipos de invocaciones. Por ejemplo, devolver JSON si tal o cual Header existe, o devolver Bytes etc.

El ApiGateway es como una mascara en frente de una Api o Función, de hecho, se considerá como una "Facade" (Fachada), y efectivamente lo es. Nuestra aplicación podría lidiar con el ApiGateway y esta podrá decidir en base a los argumentos dados y al tipo de contenido esperado para finalmente hacer la llamada a su función destino o a su api destino.

Si por ejemplo quien llama a la ApiGateway expone un encabezado "Accept: image/jpeg" entonces el ApiGateway podrá tomar lo que la api destino ha emitido y convertirlo para entregar los bytes de la imagen, por el contrario podria devolver solo texto en formato JSON.

Como ejemplos de ApiGateways tenemos:

2.1) Amazon Api Gateway
2.2) Kong
2.3) IBM Bluemix
2.4) Google Endpoints

Caso de Ejemplo de un ApiGateway


En la siguiente imagen muestro el diseño de una ApiGateway que dará Endpoints (Urls para usar) para los siguientes servicios (ver imagen adjunta). De esta imagen tomaré el endpoint "Media", el cual se define así:



























(Imagen: DISEÑO DE ENDPOINTS)


Ejemplo:

Siguiendo la imagen anterior, pondré el foco en el recurso "/page/media", el cual procesará un GET.

https://<ALGUN_IDENTIFICADOR>.amazon.aws.com/<version>/page/media/imagen.png/1

En donde "ALGUN_IDENTIFICADOR" será dado por la ApiGateway y la "<version>" será dada al momento de hacer despliegue (Deploy, algun equivalente lejano seria: "compilar").  

Cuando se  inserta esta URL en un elemento "<img src='URL' />" entonces suceden dos cosas:
  
1) El ApiGateway recibe una petición GET a ese Endpoint (ver la imagen abajo)
2) El request trae un Header: "Accept:  image/jpeg" (por el hecho de venir de un tag IMG)
En base a eso entonces el ApiGateway sabrá a qué función o Api invocar y sabrá además cómo procesar el resultado de la función o Api, en este caso retornando los Bytes de la imagen.  

Podriamos por ejemplo programar el ApiGateway para que devuelva contenido JSON si el Header "Accept" no esta presente. Este caso podría darse cuando pegamos la URL de la imagen en la barra de direcciones del browser, lo cual seria diferente a que un elemento IMG la invoque (en este caso el request traería el Header "Accept: image/jpeg"). 

Ahora, mostraré qué hace la función que sirve al Endpoint de la URL de arriba (/page/media/..).  Este Endpoint invoca a una Función Lambda de Amazon, la cual tiene algunos detalles de seguridad que no cubriré acá pero que hacen referencia a un Rol que se le debe dar a esta para que tenga permisos para ejecutarse y para acceder a otros recursos.

El Flujo de un ApiGateway

Acá muestro el flujo que da vida al Endpoint "/page/media" dentro de un diseño con Amazon Api Gateway:



 "Method Request" gobierna la configuración de los argumentos de la Url. Un argumento puede ser una variable en la URL ("?abc=123&xyz=890)", o puede ser un nombre especial entre llaves como es el caso de esta Api de ejemplo: /page/media/{attribute_name}/{id}.

"Integration Request" recibe los argumentos, el cuerpo (Body) de la petición (Request) y decide el método a usarse: Si invocará una función lambda u otra Api (y otras opciones), además podrá mapear o reasignar las variables entregadas contra las variables que la función destino o api destino necesitan. 

"Lambda WhMarketingApiMedia" es el nombre de la función que se esta ejecutando.

"Integration Response" procesará lo que la función retorna. Esta podría retornar los Bytes de la imagen o un objeto JSON aunque es mejor que esta ultima opción sea la preferida porque nos dará el poder de elegir elementos de la respuesta ayudando así a procesar lo que queremos devolver. 

"Method Response" se encarga de lidiar con Headers, para así responder de acuerdo a estos. Es acá donde finalmente se entrega la información.


La Función Lambda


Nuestra función Lambda hace lo siguiente (escrita en NodeJS):


La función lambda sobre estas lineas es invocada con unos argumentos (event, context, callback) que son procesados por el motor del ApiGateway y del mecanismo de Lambda Functions de Amazon.  Nuestra función se ejecutará dentro de un contenedor seguro gestionado por Amazon.

El argumento "event" es creado por nosotros en la configuración del ApiGateway, dentro de "Integration Request".

El Argumento "context" es entregado y manejado por Amazon.

El argumento "callback" es una función que debemos invocar cuando nuestra función ha terminado.

Lo que el cuerpo de la función hace es buscar en un "Bucket S3" de amazón por un nombre de archivo indicado en los argumentos de llamada (dentro de "event").  Un Bucket S3 es un almacen de contenido de Amazon.

Como resultado devolvemos los Bytes de la imagen, pudimos haber devuelto una estructura JSON, pero para el caso particular de las imagenes se debe entregar codificado en base64, debido a que recibirá un tratamiento especial por el ApiGateway.

Ejemplo de Diagrama mas complejo de una aplicación real diseñada en la Nube


Esta primera versión ilustra la idea principal. Queremos crear una LandingPage para un cliente dado su ID de cliente. Las piezas estan distribuidas en diferentes servicios de Amazon (BucketS3, DynamoDb, Funciones Lambda, Etc).


Luego acá una idea mas detallada de cómo quedó el diseño finalizado, ilustrando las piezas usadas y sus dependencias:



Funciona así:

Una URL es ejecutada en el browser y esta presenta a un LandingPage que es construido con información que se sacó de una tabla en DynamoDb. Esta landingpage usa imagenes, las cuales son referenciadas por su URL.

Las imagenes se obtienen de BucketsS3 y se piden mediante una Url especial diseñada para entregar Bytes de estas (Endpoint "/page/media/..").

El Formulario se fabrica en una parte especial de la función que crea la pagina (FormBuilder.js) y se incrusta en el contenido Html. Es bien sabido que cuando un formulario es "enviado" entonces hará una llamada de tipo POST a una URL, pues bien, esta URL también ha sido considerada en el diseño de endpoints (ver imagen "Diseño de Endpoints").

Una función lambda (la que maneja el Post) es especializada en capturar el POST, guardarlo en una tabla de DynamoDB y nada mas...

La tabla de DynamoDb ha sido diseñada para que tenga un "Trigger" que será ejecutado cuando un registro sea insertado o modificado, en tal situación se ejecutará otra función lambda que examinará el dato modificado y en consecuencia le enviará un email a alguien.

Finalmente:



¿ Y qué hacemos con esa Horrible URL ?

Dos vías,

1) puedes crear un CNAME para el hostname, pero los recursos serán aún visibles, es decir, si hacemos un CNAME para que sustituya el nombre del host quedaría así:

    http://129898192.apigateway.aws.com/page/1

con un CNAME quedaría asi:

   http://algo.mipagina.com/page/1

en donde el CNAME sería así:

   algo.mipagina.com => 129898192.apigateway.aws.com

2) Otra solución sería implementar un Proxy desde el servidor de una pagina que provea una url amigable.

 por ejemplo:

Cuando alguien acceda a "http://abc.com/xyz/123" entonces invocamos al recurso indicado via CURL desde el servidor, a modo de Proxy.

Este es mi método preferido, por la razón del uso de SSL y los certificados. Si creamos un certificado SSL para un dominio abc.com entonces la solución basada en CNAME no funcionará, pero esta última sí.  

jueves, 9 de marzo de 2017

Qué es el Software en la Nube (Y qué no es)


 Video de Ejemplo - Tutorial - Cómo crear una Api usando el ApiGateway de Aws.






Hoy en día el término "Software en la Nube" es ampliamente utilizado tanto por clientes como por proveedores de software, mayoritariamente mal utilizado, usándolo solo para hacerse de Marketing para vender software obsoleto y monolítico que realmente no es Software en la Nube, que se piensa que lo es simplemente por el hecho de haber instalado una aplicación en un servidor mal instalado "en la nube" (lease: en la red de algún proveedor de servidores como Amazon AWS, por ejemplo) . Aquí espero aclarar la idea sin mayor profundidad.

Lo que hiciste...no es Software en la Nube.


No es Software en la Nube cuando se ha rescrito el mismo software de escritorio pero ahora para la web con algún Framework como Laravel, YiiFramework, etc.

En este caso el software sigue teniendo una arquitectura monolítica (y no me refiero al Framework, sino a cómo lo subutiliza el desarrollador). La famosa "clase con 500 métodos" o mas, que según su desarrollador "es orientada a objetos" por el hecho de haber creado una enorme clase que se parece mas a un programa hecho con QBasic pero con el término "class" en su cabecera sin el menor control de dependencias ni componentización. Aún así este tipo de aplicaciones son vendidas como tal por el simple hecho de que se esta ejecutando en un VPC de Amazon (por ejemplo).

La causa de esta falla de diseño mal etiquetado como "Software en la Nube" recae en la improvisación del desarrollador, la falta de preparación y estudio, y por sobre todo la falta de capacidad de abstracción y síntesis, esta última es adquirida mediante la lectura por tanto a la generación "Whatsapp" le será muy difícil lograr un real desarrollo en la nube.

 

Tu LAMP o WAMP tampoco garantizan que realmente sea Software en la Nube.

 

Muchos desarrolladores consiguen un proveedor de servidores virtuales (una VPC, Linux o Windows, ej: Amazon Ec2) e instalan allí su aplicación web, supongamos que ha sido bien diseñada con algún Framework como YiiFramework o Laravel, me refiero a alguien con experiencia en software y que ha diseñado una aplicación componentizada y realmente orientada a objetos. Aún esto no garantiza que sea Software en la Nube, esto simplemente es una Aplicación Web ejecutandose en el servidor de otra empresa.

El hecho de que el servidor sea "configurable en la nube" no significa que la "la aplicación exista en la nube".

De esto último salen algunas expresiones populares como "El software en la nube solo corre en el computador de otra persona". Lo cual es cierto, debido al mal uso del término "Software en la Nube".

 

Cómo se hace el verdadero Software en la Nube. Microservices y API Gateways.

 

En primer lugar, siempre estarán las personas que dirán "si, pero los microservices también se ejecutan en el servidor de otro". Es simplemente una manera que ellos tienen para opacar aquello que no quieren entender.

A pesar que los Microservices son funciones computarizadas que existen en otro servidor podemos decir que no equivale a tener a un servidor VPC dedicado para proveerlas.

La diferencia es que los Microservices que una verdadera aplicación en la Nube utiliza en su conjunto para proveer una solución estan distribuidas y gestionadas por una capa de software que no nos corresponde tocar, si existen en servidores (de Amazon, por ejemplo) pero de una forma virtualizada (utilizando el término "virtual" con real exactitud) en el sentido de que se nos presenta una capa homogenea de funciones disponibles para ser usadas, como si estuvieran en un solo sitio (la parte "virtual") pero en realidad estan distribuidas, gestionadas para manejar carga y disponibilidad.

Por ejemplo, si una aplicación web hecha con Microservices usa diez de estos para proveer la funcionalidad estos podrian estar distribuidos en diferentes servidores, incluso la distribución podria cambiar sin que la aplicación web lo note. El LoadBalancing es casi transparente e implícito. Esto se aleja muchísimo del esquema en donde tenemos un servidor fijo que las provea. La capa que provee los Microservices es dinámica, es componentizada y aislada por fuerza bruta, obligando a tener una arquitectura realmente distribuida en la nube. Aquí nace el verdadero Software en la Nube.


Qué es un Microservice.


Un Microservice es una función que existe en alguna parte en la nube y que realiza una tarea específica. En Amazon AWS se le conocen como AWS Lambda Functions y se accede a ellas mediante un API Gateway o son invocadas por eventos de software (IOT, Database Triggers en DynamoDB, etc).

Por ejemplo, este esquema grafica el uso de una Función Lambda para proveer una LandingPage de un cliente:


En este diagrama he diseñado una API RESTFUL mediante el uso de un API GATEWAY que provee una URL para que un sitioweb pueda pedirle una página dado su ID.

La página es creada por una Función Lambda (GetLandingPage), que a su vez invoca a otros componentes como DynamoDB (para buscar alli los datos de la página, dado su ID) y un "S3 Bucket" de Amazon, de donde se sacan algunas piezas secundarias para su creación.

Qué es un Api Gateway.


Un API Gateway es una capa de software que permite crear interfaces RESTful usadas para invocar funciones. El ApiGateway provee Urls, cada Url puede ser usada para saber cómo invocar a una funcion determinada. El ApiGateway puede manipular lo que la función recibe y lo que retorna, lo cual le da la habilidad de que una sola función pueda servir a diferentes formas de invocación.

Por ejemplo, si la función acá graficada (arriba) es invocada mediante una Url específica entonces devolverá datos Html directos para ser usados en un Browser.

https://198n29j99811.execute-api.us-east-1.amazonaws.com/test/page/5

Si agregamos un argumento en la Url (ejemplo "abc"), entonces el ApiGateway podrá retornar la forma JSON de la data devuelta por la misma función que sirvió a la Url anterior (arriba).

https://198n29j99811.execute-api.us-east-1.amazonaws.com/test/page/abc/5

Ambas Url son consideradas "Resources" en la terminología del ApiGateway, y podrian invocar a la misma función, pero cada recurso retornará algo distinto, incluso podria modificar los argumentos de entrada a la función o la data que esta retorna, como por ejemplo retornar JSON en vez de Html.

La aplicación final hecha con Microservices.


Finalmente tenemos una aplicación web, o una interfaz RESTful (una Api), que esta alojada realmente en la Nube. En este ejemplo no hay servidores VPC ejecutandose en ninguna parte, no tenemos un LAMP o un WAMP corriendo webservices (aunque Amazon los provee de forma dinámica), todas las funciones estan distribuidas, el ApiGateway es provisto por Amazon AWS y junta a todas las piezas. El cliente final ve una aplicación web funcionando sin estar alojada en ningun servidor específico.

 

Cómo Beneficia al Proceso de Desarrollo de Software


Una persona puede dedicarse a programar solo las funciones (microservices) siguiendo lineamientos del arquitecto de software sin lidiar con interfaces web ni con diseño de Urls. La lógica del negocio reside acá.

Otra persona puede dedicarse a crear la estructura URL mediante la cual se va a acceder a la aplicación web (la interfaz de la Api) sin conocer detalles de cómo las funciones operan. La lógica del negocio se complementa acá.

Un diseñador de interfaces Web podria diseñar la UI, la cual consume los servicios que el ApiGateway le da. Podria usar cualquier framework orientado a diseño de interfaces web que tenga capacidad de lidiar con llamadas RESTful. ¿ Y Dónde se aloja esta "página web" ? Podria ser provista por otra función dedicada a presentar contenido HTML, también gestionada por el ApiGateway. Si piensas que para esto instalarás un servidor LAMP para allí instalar Yii Framework...pues habrás echado al piso el diseño en la nube. En cambio, la arquitectura de los Lambda Services de Amazon AWS permite que puedas crear un directorio con todos los componentes necesarios que al momento de publicar la función estarán disponibles por ejemplo para proveer un web framework de tipo NodeJS o Java.

Un diseñador de pruebas podria usar las mismas Url del ApiGateway para realizar casos de prueba. Las invocaciones podrian ser realizadas dentro de otra función (microservice).

En resumen, toda la aplicación web residirá en Microservices.


Complementos


Como complemento, Amazon AWS provee los siguientes servicios:

1. Lambda Functions (microservices, donde reside la lógica y código)
2. Api Gateway (que provee las URL e invoca a las funciones lambda)
3. S3 buckets (para guardar archivos, imagenes, usados por funciones)
4. DynamoDB (una base de datos NO-SQL, invocada por funciones)