Sitio Web Serverless con AWS

Una aplicación web requiere, típicamente, de una infraestructura para alojar los servidores web y de base de datos. Y para atender la demanda de los usuarios y garantizar el rendimiento adecuado, dichos recursos deben estar disponibles las 24 horas del día y diseñados para escalar de forma inmediata, lo que supone un gasto innecesario y uso ineficiente de recursos en horarios con poca carga o sin demanda alguna.

Adicional, la administración de tal arquitectura representa un reto de gran complejidad para las organizaciones. Por tal razón el modelo de pago por uso (pay as you go) que propone la nube ha ganado mucha popularidad, pues aparte del beneficio económico, las tareas de administración de la infraestructura física se trasladan a proveedores como Amazon, Microsoft, Google, entre otros. Aun así, las organizaciones son responsables de aprovisionar, monitorear y administrar los distintos recursos.

En tal sentido, la arquitectura denominada serverless ha cobrado gran interés, pues permite a las organizaciones enfocarse en el desarrollo de aplicaciones o nuevas funcionalidades y despreocuparse por completo de cualquier actividad relacionada con la infraestructura como aprovisionar, parchar o manejar estrategias de alta disponibilidad o escalabilidad. En este artículo se explicará la construcción de un sitio web a través de esta arquitectura serverless empleando servicios de AWS (Amazon Web Services).

A continuación el diagrama de la arquitectura propuesta:


La aplicación contará con la funcionalidad de agregar, borrar y listar datos de clientes. Se usará Angular para desarrollar las páginas web al tratarse de un framework que no requiere procesamiento del lado del servidor sino del lado del cliente, lo cual permite hacer uso de la propiedad de Static website hosting de S3. Y se empleará DynamoDB para almacenar la información de los clientes.

Y como se observa en el diagrama, se utilizará Lambda para las tareas de procesamiento del lado del servidor y por medio de API Gateway se tendrá acceso a las funciones Lambda desde las páginas en Angular. Cabe mencionar, que cada uno de estos servicios no requiere administración directa de servidores o infraestructura, sino que AWS garantizará el aprovisionamiento de estos, tanto como para hospedar el sitio web como para escalar y proveer de alta disponibilidad al mismo.

Amazon DynamoDB

Es una de las varias opciones que provee AWS para el almacenamiento o persistencia de los datos. Consiste en una base de datos NoSQL documental y llave-valor. Entre sus características se encuentra el auto-escalamiento, respaldos automáticos y recientemente el soporte de transacciones ACID. Para la aplicación se creará la siguiente tabla en la región US-East (N. Virginia):

Creación de tabla en DynamoDB

No es necesario definir otras columnas dada la naturaleza de DynamoDB que le permite aceptar cualquier estructura de datos. Opcionalmente, desmarcar la casilla de Use default settings, para modificar a On-demand el modo de capacidad de Escritura/Lectura. En este modo se paga únicamente por el consumo o demanda generada, a diferencia del modo Provisioned, en el cual se define una capacidad estimada de reserva de recursos para garantizar un rendimiento deseado. Dejar el resto de las características con su configuración predeterminada y presionar el botón Create.

AWS Lambda

Con AWS Lambda los desarrolladores se enfocan en la lógica de la aplicación en vez de estimar o administrar la infraestructura subyacente. Como plataforma serverless cuenta con alta disponibilidad, tolerancia a fallas, escalabilidad y elasticidad. Adicional, se minimiza costos al pagar, únicamente, por el tiempo de computo consumido. Actualmente existe soporte para C# NET Core, Go, Java, Node.js, Python y Ruby.

En este caso, se crearán tres funciones a partir de la opción Author from scratch presentada en la consola de AWS. A su vez se hará uso de Node.js 8.10 (versión estable más reciente al escribir este artículo) como Runtime. También se debe crear un Role de IAM para otorgar permisos a Lambda para acceder a otros servicios de AWS, este rol se utilizará para las tres funciones.

1. Name: saveClient

Definir permisos seleccionando la opción Create a custom role, esto abrirá una nueva ventana en la cual se dejan los valores predeterminados.

Role con permisos default para AWS Lambda

Tomar nota del Role Name para asociarlo a las dos funciones restantes. Observar que los permisos predeterminados permiten la creación de logs.

Tras crear el nuevo rol, presionar el botón Create function. Esto desplegará una nueva pantalla con varias opciones, entre ellas la de Function Code en la cual es posible ubicar el código de la función:

var AWS = require('aws-sdk'), uuid = require('uuid'),
documentClient = new AWS.DynamoDB.DocumentClient();
exports.handler = (event, context, callback) => {
var params = {
Item : {
"Id" : uuid.v1(),
"nit" : event.nit,
"name": event.name,
"address": event.address,
"phone": event.phone
},
TableName : 'cliente'
};
documentClient.put(params, function(err, data){
callback(err, {
"message":"Detalles del Cliente guardados exitosamente."
});
});
};

Como se observa en el código anterior, se hace uso del AWS SDK para instanciar un cliente de DynamoDB. Y en este caso por medio del método put, se recibe como primer argumento un objeto en JavaScript con formato de registros y nombre de tabla; y como segundo argumento una función que retorna un error o bien los datos insertados. Se empleará mismo procedimiento para crear las dos funciones restantes.

2. Name: deleteClient

var AWS = require(‘aws-sdk’),
documentClient = new AWS.DynamoDB.DocumentClient();
exports.handler = (event, context, callback) => {
console.log(“Received event: “ + JSON.stringify(event));
var params = {
TableName: ‘application_users’,
Key: {
“nit”: event[‘queryStringParameters’][‘nit’]
}
};
documentClient.delete(params, function(err, data) {
if (err) {
callback(err, null);
}
else {
var response = {
“statusCode”: 200,
“headers”: {
“content-type”: “application/json”,
“Access-Control-Allow-Origin”: “*”
},
“body”: JSON.stringify({ ‘msg’: ‘Cliente borrado exitosamente.’ }),
“isBase64Encoded”: false
};
callback(null, response);
}
});
};

3. Name: listClient

var AWS = require(‘aws-sdk’),
documentClient = new AWS.DynamoDB.DocumentClient();
exports.handler = (event, context, callback) => {
var params = {
TableName : ‘cliente’
};
documentClient.scan(params, function(err, data){
if(err){
callback(err, null);
}else{
callback(null, data.Items);
}
});
};

API Gateway

En este punto, las funciones Lambda cumplen con la lógica de la aplicación, pero no pueden ser accedidas de forma pública por HTTP. De tal manera, API Gateway provee de una interfaz simple que permite crear URL públicas para invocar en este caso cada función Lambda. Y de esta forma se logra crear un API o “puerta frontal” hacia las aplicaciones o funcionales del back-end.

En la consola de AWS, ubicar el servicio de API Gateway y crear una API con las siguientes opciones:

Creación de API Gateway

Tras presionar el botón Create API, se despliega un editor que permite definir recursos y métodos que siguen las convenciones REST. Para el ejemplo, se debe crear un recurso a partir de Actions -> Create Resource:

Creación de un recurso en API Gateway

Aparecerá la entrada /cliente en el área de Resources, para crear los métodos HTTP se debe seleccionar dicha entrada y en Actions elegir Create Method. Lo anterior mostrará un listbox con varios métodos, en este caso seleccionar POST y presionar el cheque para resguardar la configuración.

Creación de un método en API Gateway

Al presionar el cheque se despliega una pantalla que facilita la configuración del método correspondiente, en este caso se prosigue de esta manera:

Configuración de un método en API Gateway

Al hacer clic en el botón Save, se mostrará una especie de advertencia o mensaje indicando si se está de acuerdo en dar permisos a API Gateway para invocar funciones Lambda. Presionar OK para proseguir.

De forma similar, se debe crear dos métodos con la siguiente configuración:

Eliminar Clientes

Method: Delete
Integration Type: Lambda function
Lambda Region: us-east-1
Lambda Function: deleteClient
Use default timeout: checked

Listar Clientes

Method: Get
Integration Type: Lambda function
Lambda Region: us-east-1
Lambda Function: listClient
Use default timeout: checked

Validaciones de API

Antes de invocar las APIs desde la aplicación web, por medio de la opción Test de API Gateway se puede validar el funcionamiento de cada método. En este caso se hará un ejemplo a través del método POST, y se puede seguir similares pasos para verificar el resto de los métodos, lo cual se deja como ejercicio.

Test de método de API Gateway

Al presionar Test, se mostrarán varias secciones en el área derecha de la pantalla. Si la operación fue exitosa en el Response Body se debe leer el mensaje:

Resultado exitoso de ejecución de método de API Gateway

Adicional, en la tabla de DynamoDB debe existir la entrada del registro respectivo:

Registro en tabla de DynamoDB

En caso de haber existido un error, es posible usar las salidas presentadas en la sección de Logs para iniciar con las indagaciones del caso.

Despliegue de API

Al confirmar el correcto funcionamiento de cada método HTTP y cada función Lambda correspondiente, se procede a desplegar el API para tener acceso a ella desde la aplicación web. De tal forma, seleccionar el recurso /cliente y en Actions -> Deploy API para ingresar algunos detalles:

Detalles para despliegue de API

Tras unos segundos se completa el despliegue y en la pantalla se muestra una URL para acceder al API entre otras configuraciones las cuales quedan fuera del alcance de este artículo. Con esto se concluye con la funcionalidad de la aplicación serverless, que hace uso de DynamoDB para almacenar datos, funciones Lambda para manipular datos y API Gateway para invocar recursos. En una próxima entrada se cubrirá el desarrollo de la interfaz de usuario por medio de Angular y el hosting del sitio en S3 para obtener lo siguiente: