7 cosas que debes saber al comenzar con las API sin servidor

Índice
  1. ¿Cómo creo un nuevo proyecto sin servidor?
  2. ¿Cómo ejecuto y depuro funciones sin servidor localmente?
  3. ¿Cómo instalo dependencias?
  4. ¿Cómo me conecto a servicios de terceros?
  5. Where can I save connection strings?
  6. How do I customize the URL path?
  7. How can I deploy to the cloud?
  8. Are you ready to make Serverless APIs?

Quiero que te tomes un segundo y pienses en Twitter, y lo pienses en términos de escala. Twitter tiene 326 millones de usuarios . En conjunto, creamos ~6000 tweets cada segundo . Cada minuto, se crean 360.000 tweets. Eso suma casi 200 mil millones de tweets al año. Ahora bien, ¿qué pasaría si los creadores de Twitter se hubieran paralizado sobre cómo escalar y ni siquiera hubieran empezado?

Ese soy yo en cada idea de startup que he tenido, y es por eso que adoro tanto la tecnología sin servidor: ¡se encarga de los problemas de escalamiento y me deja a mí construir el próximo Twitter!

Como puede ver en lo anterior, escalamos de uno a siete servidores en cuestión de segundos, a medida que llegan más solicitudes de los usuarios. También puede escalar eso fácilmente.

Entonces, creemos una API que se escalará instantáneamente a medida que ingresen más y más usuarios y aumente nuestra carga de trabajo. Lo haremos respondiendo las siguientes preguntas:

  • ¿Cómo creo un nuevo proyecto sin servidor?
  • ¿Cómo ejecuto y depuro código localmente?
  • ¿Cómo instalo dependencias?
  • ¿Cómo me conecto a servicios de terceros?
  • ¿Dónde puedo guardar cadenas de conexión?
  • ¿Cómo personalizo la ruta URL?
  • ¿Cómo puedo implementar en la nube?

¿Cómo creo un nuevo proyecto sin servidor?

Con cada nueva tecnología, necesitamos descubrir qué herramientas están disponibles para nosotros y cómo podemos integrarlas en nuestro conjunto de herramientas existente. Al comenzar con la tecnología sin servidor, debemos considerar algunas opciones.

Primero, podemos usar el viejo navegador para crear, escribir y probar funciones. Es poderoso y nos permite codificar dondequiera que estemos; todo lo que necesitamos es una computadora y un navegador en funcionamiento. El navegador es un buen punto de partida para escribir nuestra primera función sin servidor.

A continuación, a medida que se acostumbre más a los nuevos conceptos y se vuelva más productivo, es posible que desee utilizar su entorno local para continuar con su desarrollo. Normalmente necesitarás soporte para algunas cosas:

  • Escribir código en el editor de su elección
  • Herramientas que hacen el trabajo pesado y generan el código repetitivo por usted
  • Ejecutar y depurar código localmente
  • Soporte para implementar rápidamente su código

Microsoft es mi empleador y he creado principalmente aplicaciones sin servidor utilizando Azure Functions, por lo que durante el resto de este artículo continuaré usándolas como ejemplo. Con Azure Functions , tendrá soporte para todas estas características cuando trabaje con las herramientas principales de Azure Functions que puede instalar desde npm .

npm install -g azure-functions-core-tools

A continuación, podemos inicializar un nuevo proyecto y crear nuevas funciones utilizando la CLI interactiva:

Si su editor preferido es VS Code , también puede usarlo para escribir código sin servidor. De hecho, existe una gran extensión para ello.

Una vez instalado, se agregará un nuevo ícono a la barra lateral izquierda: ¡aquí es donde podemos acceder a todas nuestras extensiones relacionadas con Azure! Todas las funciones relacionadas se pueden agrupar en el mismo proyecto (también conocido como aplicación de funciones). Esto es como una carpeta para agrupar funciones que deben escalarse juntas y que queremos administrar y monitorear al mismo tiempo. Para inicializar un nuevo proyecto usando VS Code, haga clic en el ícono de Azure y luego en el ícono de la carpeta .

Esto generará algunos archivos que nos ayudarán con la configuración global. Repasemos eso ahora.

host.json

Podemos configurar opciones globales para todas las funciones del proyecto directamente en el host.jsonarchivo.

En él, nuestra aplicación de funciones está configurada para utilizar la última versión del tiempo de ejecución sin servidor (actualmente 2.0). También configuramos funciones para que expiren después de diez minutos estableciendo la functionTimeoutpropiedad en 00:10:00 : el valor predeterminado para eso es actualmente cinco minutos ( 00:05:00).

En algunos casos, es posible que queramos controlar el prefijo de ruta de nuestras URL o incluso modificar la configuración, como la cantidad de solicitudes simultáneas. Azure Functions incluso nos permite personalizar otras funciones como el registro healthMonitory diferentes tipos de extensiones.

Aquí hay un ejemplo de cómo configuré el archivo:

// host.json{  "version": "2.0",  "functionTimeout": "00:10:00",  "extensions": {  "http": {    "routePrefix": "tacos",    "maxOutstandingRequests": 200,    "maxConcurrentRequests": 100,    "dynamicThrottlesEnabled": true  }}}

Configuraciones de la aplicación

La configuración de la aplicación es una configuración global para administrar el tiempo de ejecución, el idioma y la versión, las cadenas de conexión, el acceso de lectura/escritura y la implementación de ZIP, entre otros. Algunas son configuraciones requeridas por la plataforma, como FUNCTIONS_WORKER_RUNTIME, pero también podemos definir configuraciones personalizadas que usaremos en el código de nuestra aplicación, como DB_CONNlas que podemos usar para conectarnos a una instancia de base de datos.

Mientras desarrollamos localmente, definimos estas configuraciones en un archivo llamado local.settings.jsony accedemos a ellas como cualquier otra variable de entorno.

Nuevamente, aquí hay un fragmento de ejemplo que conecta estos puntos:

// local.settings.json{  "IsEncrypted": false,  "Values": {    "AzureWebJobsStorage": "your_key_here",    "FUNCTIONS_WORKER_RUNTIME": "node",    "WEBSITE_NODE_DEFAULT_VERSION": "8.11.1",    "FUNCTIONS_EXTENSION_VERSION": "~2",    "APPINSIGHTS_INSTRUMENTATIONKEY": "your_key_here",    "DB_CONN": "your_key_here",  }}

Proxies de funciones de Azure

Los proxy de Azure Functions se implementan en el proxies.jsonarchivo y nos permiten exponer múltiples aplicaciones de funciones bajo la misma API, así como modificar solicitudes y respuestas. En el código siguiente, publicamos dos puntos finales diferentes en la misma URL.

// proxies.json{  "$schema": "http://json.schemastore.org/proxies",  "proxies": {    "read-recipes": {        "matchCondition": {        "methods": ["POST"],        "route": "/api/recipes"      },      "backendUri": "https://tacofancy.azurewebsites.net/api/recipes"    },    "subscribe": {      "matchCondition": {        "methods": ["POST"],        "route": "/api/subscribe"      },      "backendUri": "https://tacofancy-users.azurewebsites.net/api/subscriptions"    }  }}

Cree una nueva función haciendo clic en el ícono del trueno en la extensión.

La extensión utilizará plantillas predefinidas para generar código, según las selecciones que hicimos: idioma, tipo de función y nivel de autorización.

Usamos function.jsonpara configurar qué tipo de eventos escucha nuestra función y, opcionalmente, para vincularnos a fuentes de datos específicas. Nuestro código se ejecuta en respuesta a desencadenantes específicos que pueden ser de tipo HTTP cuando reaccionamos a solicitudes HTTP (cuando ejecutamos código en respuesta a la carga de un archivo en una cuenta de almacenamiento). Otros activadores utilizados comúnmente pueden ser de tipo cola , para procesar un mensaje cargado en una cola o activadores de tiempo para ejecutar código en intervalos de tiempo específicos. Los enlaces de funciones se utilizan para leer y escribir datos en fuentes de datos o servicios como bases de datos o enviar correos electrónicos.

Aquí, podemos ver que nuestra función está escuchando solicitudes HTTP y obtenemos acceso a la solicitud real a través del objeto llamado req.

// function.json{  "disabled": false,  "bindings": [    {      "authLevel": "anonymous",      "type": "httpTrigger",      "direction": "in",      "name": "req",      "methods": ["get"],      "route": "recipes"    },    {      "type": "http",      "direction": "out",      "name": "res"    }  ]}

index.jses donde implementamos el código para nuestra función. Tenemos acceso al objeto de contexto, que utilizamos para comunicarnos con el tiempo de ejecución sin servidor. Podemos hacer cosas como registrar información, establecer la respuesta para nuestra función y leer y escribir datos del bindingsobjeto. A veces, nuestra aplicación de funciones tendrá varias funciones que dependen del mismo código (es decir, conexiones de bases de datos) y es una buena práctica extraer ese código en un archivo separado para reducir la duplicación de código.

//Index.jsmodule.exports = async function (context, req) {  context.log('JavaScript HTTP trigger function processed a request.');  if (req.query.name || (req.body  req.body.name)) {      context.res = {          // status: 200, /* Defaults to 200 */          body: "Hello " + (req.query.name || req.body.name)      };  }  else {      context.res = {          status: 400,          body: "Please pass a name on the query string or in the request body"      };  }};

¿Quién está emocionado de probar esto?

¿Cómo ejecuto y depuro funciones sin servidor localmente?

Cuando usamos VS Code, la extensión Azure Functions nos brinda gran parte de la configuración que necesitamos para ejecutar y depurar funciones sin servidor localmente. Cuando creamos un nuevo proyecto usándolo, .vscodese creó automáticamente una carpeta para nosotros, y aquí es donde está contenida toda la configuración de depuración. Para depurar nuestra nueva función, podemos usar la paleta de comandos ( Ctrl+ Shift+ P) filtrando por Depurar: Seleccionar e iniciar depuración , o escribiendo debug.

Una de las razones por las que esto es posible es porque el tiempo de ejecución de Azure Functions es de código abierto y se instala localmente en nuestra máquina al instalar el azure-core-toolspaquete.

¿Cómo instalo dependencias?

Es probable que ya sepas la respuesta a esta pregunta si has trabajado con Node.js. Como en cualquier otro proyecto de Node.js, primero debemos crear un package.jsonarchivo en la carpeta raíz del proyecto. Esto se puede hacer ejecutando npm init -y : -yinicializará el archivo con la configuración predeterminada.

Luego instalamos dependencias usando npm como lo haríamos normalmente en cualquier otro proyecto. Para este proyecto, sigamos adelante e instalemos el paquete MongoDB desde npm ejecutando:

npm i mongodb

El paquete ahora estará disponible para importar en todas las funciones de la aplicación de funciones.

¿Cómo me conecto a servicios de terceros?

Las funciones sin servidor son bastante poderosas y nos permiten escribir código personalizado que reacciona a eventos. Pero el código por sí solo no ayuda mucho a la hora de crear aplicaciones complejas. El verdadero poder proviene de la fácil integración con servicios y herramientas de terceros.

So, how do we connect and read data from a database? Using the MongoDB client, we’ll read data from an Azure Cosmos DB instance I have created in Azure, but you can do this with any other MongoDB database.

//Index.jsconst MongoClient = require('mongodb').MongoClient;// Initialize authentication details required for database connectionconst auth = {  user: process.env.user,  password: process.env.password};// Initialize global variable to store database connection for reuse in future callslet db = null;const loadDB = async () = {  // If database client exists, reuse it    if (db) {    return db;  }  // Otherwise, create new connection    const client = await MongoClient.connect(    process.env.url,    {      auth: auth    }  );  // Select tacos database  db = client.db('tacos');  return db;};module.exports = async function(context, req) {  try {    // Get database connection    const database = await loadDB();    // Retrieve all items in the Recipes collection     let recipes = await database      .collection('Recipes')      .find()      .toArray();    // Return a JSON object with the array of recipes     context.res = {      body: { items: recipes }    };  } catch (error) {    context.log(`Error code: ${error.code} message: ${error.message}`);    // Return an error message and Internal Server Error status code    context.res = {      status: 500,      body: { message: 'An error has occurred, please try again later.' }    };  }};

One thing to note here is that we’re reusing our database connection rather than creating a new one for each subsequent call to our function. This shaves off ~300ms of every subsequent function call. I call that a win!

Where can I save connection strings?

When developing locally, we can store our environment variables, connection strings, and really anything that’s secret into the local.settings.json file, then access it all in the usual manner, using process.env.yourVariableName.

local.settings.json{  "IsEncrypted": false,  "Values": {    "AzureWebJobsStorage": "",    "FUNCTIONS_WORKER_RUNTIME": "node",    "user": "your-db-user",    "password": "your-db-password",    "url": "mongodb://your-db-user.documents.azure.com:10255/?ssl=true"  }}

In production, we can configure the application settings on the function’s page in the Azure portal.

However, another neat way to do this is through the VS Code extension. Without leaving your IDE, we can add new settings, delete existing ones or upload/download them to the cloud.

How do I customize the URL path?

With the REST API, there are a couple of best practices around the format of the URL itself. The one I settled on for our Recipes API is:

  • GET /recipes: Retrieves a list of recipes
  • GET /recipes/1: Retrieves a specific recipe
  • POST /recipes: Creates a new recipe
  • PUT /recipes/1: Updates recipe with ID 1
  • DELETE /recipes/1: Deletes recipe with ID 1

The URL that is made available by default when creating a new function is of the form http://host:port/api/function-name. To customize the URL path and the method that we listen to, we need to configure them in our function.json file:

// function.json{  "disabled": false,  "bindings": [    {      "authLevel": "anonymous",      "type": "httpTrigger",      "direction": "in",      "name": "req",      "methods": ["get"],      "route": "recipes"    },    {      "type": "http",      "direction": "out",      "name": "res"    }  ]}

Moreover, we can add parameters to our function’s route by using curly braces: route: recipes/{id}. We can then read the ID parameter in our code from the req object:

const recipeId = req.params.id;

How can I deploy to the cloud?

Congratulations, you’ve made it to the last step! Time to push this goodness to the cloud. As always, the VS Code extension has your back. All it really takes is a single right-click we’re pretty much done.

The extension will ZIP up the code with the Node modules and push them all to the cloud.

While this option is great when testing our own code or maybe when working on a small project, it’s easy to overwrite someone else’s changes by accident — or even worse, your own.

Don’t let friends right-click deploy!
— every DevOps engineer out there

A much healthier option is setting up on GitHub deployment which can be done in a couple of steps in the Azure portal, via the Deployment Center tab.

Are you ready to make Serverless APIs?

This has been a thorough introduction to the world of Servless APIs. However, there’s much, much more than what we’ve covered here. Serverless enables us to solve problems creatively and at a fraction of the cost we usually pay for using traditional platforms.

Chris has mentioned it in other posts here on , but he created this excellent website where you can learn more about serverless and find both ideas and resources for things you can build with it. Definitely check it out and let me know if you have other tips or advice scaling with serverless.

SUSCRÍBETE A NUESTRO BOLETÍN 
No te pierdas de nuestro contenido ni de ninguna de nuestras guías para que puedas avanzar en los juegos que más te gustan.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Subir

Este sitio web utiliza cookies para mejorar tu experiencia mientras navegas por él. Este sitio web utiliza cookies para mejorar tu experiencia de usuario. Al continuar navegando, aceptas su uso. Mas informacion